2017-01-02 4 views
0

Ich versuche, ein Code-Snippet generisch zu machen, aber ich habe Probleme, da ich nicht völlig verstehe, wie die Technik im Code funktioniert.Machen Sie diese C++ Code generische

bekam ich den Code von einer anderen Frage: C++17 construct array in stack using choosen constructor (same constructor parameter values for each array entry)

Hier ist der Code auf der ersten Reaktion dieses Beitrags basiert, ist, dass aus irgendeinem Grunde nicht mit einer Größe über 88 arbeiten: http://ideone.com/WDlNwd

#include <iostream> 
#include <utility> 

struct A1 { 
    A1() { 
     printf("A1() called\n"); 
    } 

    A1(std::size_t i) { 
     printf("A1(%d) called\n", i); 
    } 

    A1(std::size_t i, std::size_t j) { 
     printf("A1(%d, %d) called\n", i, j); 
    } 
}; 

struct A2 { 
    A2(std::size_t i, std::size_t j, double k) { 
     printf("A2(%d, %d, %lf) called\n", i, j, k); 
    } 
}; 

template <class T, size_t Size> 
class B { 
    template<typename Arg1, typename ...Args, size_t... Is> 
    B(std::index_sequence<Is...>, const Arg1 &arg1, const Args &...args) : 
    tab{ {(void(Is), arg1), args... }... } 
    {} 

    public: 

    T tab[Size]; 

    B() = default; 

    template<typename ...Args> 
    B(const Args &...args) 
     : B(std::make_index_sequence<Size>(), args...) {} 
}; 

int main() { 
    static constexpr size_t Size = 100; 
    B<A1, Size> b1(11, 17); 
    B<A1, Size> b1a(11); 
    B<A1, Size> b1b; 
    B<A2, Size> b2(11, 17, 1.2); 
    return 0; 
} 

Dank

+2

Sie sollten ein Argument nicht mehr als einmal "std ::" weiterleiten. Du weißt nie, wann das eine Bewegung provoziert. Wenn Sie das verhindern wollen, sollten Sie Argumente als 'const &' anstatt als Weiterleitungsreferenzen verwenden. –

+0

Die STL-Implementierung von std :: vector :: emplace_back() verwendet genau das gleiche Konstrukt wie meins. Ich habe das im STL-Code gefundene Muster in dem Zweck verwendet, um etwas Schlechtes zu vermeiden. Hast du ein Beispiel, wenn es einen Zug oder eine Kopie produzieren könnte? – infiniteLoop

+0

@mikeDundee Ich denke 'emplace_back' verwendet Parameter nur einmal, nein? Mein Verständnis von NicolBolas 'Kommentar ist, dass 'std :: forward' die gegebene r-Wert-Referenz nur einmal weiterleiten kann, da sie in einer ersten Verwendung verbraucht werden könnte und die Referenz dann auf ein Null-Objekt zeigen könnte ... –

Antwort

1

Die Antwort ist im Wesentlichen das gleiche wie the answer you got on the last one. Der einzige Unterschied besteht darin, dass Sie spezielle Nulldurchgangsparameter übergeben müssen. Und passen Sie die Reihenfolge der index_sequence Parameter an:

struct B { 
    A tab[100]; 

    //Note: feel free to use SFINAE to make this go away 
    //if `A` is not default-constructible. 
    B() = default; 

    template<typename ...Args> 
    B(const Args &...args) 
     : B(std::make_index_sequence<100>(), args...) {} 

private: 

    template<typename Arg1, typename ...Args, size_t... Is> 
    B(std::index_sequence<Is...>, const Arg1 &arg1, const Args &...args) 
     : tab{ {(void(Is), arg1), args... }... } {} 
}; 
+0

Vielen Dank, aber das funktioniert nicht, wenn die Parameter vom Typ std :: size_t sind: http://ideone.com/WDlNwd – infiniteLoop

+0

@mikeDundee: Separate welche Parameter Packs? Das Problem ist die engere Umwandlung von 'int'-Argumenten in' size_t'-Argumente, die list-initialization verbietet. Ich kann die Listeninitialisierungs-Dummheit nicht beheben.Sie haben also zwei Möglichkeiten: Sie können die Argumente beim Erstellen Ihrer B-Dateien (http://ideone.com/5Tpqgx) umsetzen. Oder Sie können den Typ "A" anhand der Konstruktorsyntax anstelle der Listensyntax konstruieren. Was bedeutet, dass es für Aggregate nicht funktioniert. –

+0

Ich weiß nicht, weil Ihre Lösung mit einer Array-Größe von 87 oder 88 und darunter, aber nicht darüber, arbeitet, das ist seltsam. Entschuldigung, ich verstehe nicht, wie sich die Listeninitialisierung ausdehnt, und obwohl die Indexsequenz ein variadischer Parameter war, ist dies nicht der Fall. – infiniteLoop