"Slicing" in C++?



  • Hallo,

    ich habe eine etwas "seltsame" Frage:
    ich habe eine Funktion, die in etwa so aussieht:

    setHeights(const std::vector<IndexHeightPair>& values);
    
    // IndexHeightPair sieht in etwa so aus:
    struct IndexHeightPair {
       int index;
       float height;
    };
    

    Die Funktion erwartet also einen Vektor mit Strukturen, wobei jede Struktur ein Index/Höhen Pärchen ist.
    Ich muss nun für alle Indices ZWEI Höhenwerte speichern (den ursprünlichen und modifizierten). Meine Datenstruktur zum Speichern sieht also so aus:

    struct IndexHeightPairStorage {
       int index;
       float initialheight;
       float modifiedHeight;
    };
    

    Meine Datenstruktur ist also sowas: std::vector<IndexHeightPairStorage> foo; Es soll nun setHeights() aufgerufen werden und abhängig von bestimmten Parametern einmal mit den initialHeights und einmal mit den modifiedHeights. In Pseudocode also das:

    std::vector<IndexHeightPairStorage> foo;  // Datenstruktur
    if( useInitialHeights ) {
       setHeights(foo); // Hier soll setHeights mit foo aufgerufen werden (geht so natürlich nicht, da setHeights einen Vektor 
    // mit einer Struktur erwartet, die nur EINEN Höhenwert hat). Ich bräuchte hier 
    // so eine Art slicing die sagt: Übergeb für jede Struktur nur initialHeight */
    }
    else
       setHeights(foo);  // Hier soll bei jeder Struktur nur modifiedHeight übergeben werden
    

    Kann man so ein "Struktur" Slicing irgendwie in C++ nachbauen?



  • Mit ein bisschen tricksen geht das

    template<typename T>
    void setHeights(std::vector<T> const &v, float (T::*get) = &T::height) {
      // ...
      float const height = v[i].*get;
      // ...
    }
    
    // ...
    std::vector<IndexHeightPair> v;
    setHeights(v);
    
    std::vector<IndexHeightPairStorage> v;
    setHeights(v, &IndexHeightPairStorage::modifiedHeight);
    


  • Das Interface von setHeights zu ändern halte ich in dem Fall für fragwürdig. Eher sowas in der Art:

    IndexHeightPair getInitial(IndexHeightPairStorage const& ihps)
    {
      IndexHeightPair ihp;
      ihp.index = ihps.index;
      ihp.height = ihps.initialHeight;
      return ihp;
    }
    IndexHeightPair getModified(IndexHeightPairStorage const& ihps);
    
    int main()
    {
      std::vector<IndexHeightPairStorage> storages;
      /* ... */
      std::vector<IndexHeightPair> pairs;
      if (useInitialHeights)
        std::transform(storages.begin(), storages.end(), std::back_inserter(pairs), &getInitial);
      else
        std::transform(storages.begin(), storages.end(), std::back_inserter(pairs), &getModified); 
    
      setHeights(pairs);
    }
    


  • Danke euch beiden.

    Nur eines versteh ich nicht bei pumuckls Idee: Wieso ein back_inserter? Dann stehen doch in pairs die Werte von storages in umgekehrter Reihenfolge? 😕



  • slicer schrieb:

    Nur eines versteh ich nicht bei pumuckls Idee: Wieso ein back_inserter? Dann stehen doch in pairs die Werte von storages in umgekehrter Reihenfolge? 😕

    Nein. back_inserter liefert einen Iterator, der mit push_back die elemente in den (vorher leeren) reinstopft.


Log in to reply