2016-05-03 18 views
1

Anstatt die Schaffung Vektoren wie folgt aus:Wie schreibe ich einen make_vector ähnlich wie std :: make_tuple?

std::vector<int>  v1{1,2,3}; 
    std::vector<double> v2{1.1,2.2,3.3}; 
    std::vector<Object> v3{Object{},Object{},Object{}}; 

Ich möchte sie mit einer generischen Funktion erstellen:

auto v1 = make_vector(1,2,3); 
    auto v2 = make_vector(1.1,2.2,3.3); 
    auto v3 = make_vector(Object{},Object{},Object{}); 

Ähnlich std::make_pair und std::make_tuple, hier war für einen Vektor mein Versuch:

#include <iostream> 
#include <vector> 
#include <utility> 

template <typename... T> 
auto make_vector(T&&... args) 
{ 
    using first_type = typename std::tuple_element<0, std::tuple<T...>>::type; 
    return std::vector<first_type>{std::forward<T>(args)...}; 
} 

es kompiliert, aber wenn ich versuche, es zu benutzen:

auto vec = make_vector(1,2,3); 

m.cpp: In instantiation of ‘auto make_vector(T&& ...) [with T = {int, int, int}]’: 
m.cpp:16:30: required from here 
m.cpp:8:78: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’ 
    using first_type = typename std::tuple_element<0, std::tuple<T...>>::type; 
                      ^
In file included from m.cpp:3:0: 
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’ 
    class tuple_element; 
     ^
m.cpp:9:60: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’ 
    return std::vector<first_type>{std::forward<T>(args)...}; 
                  ^
In file included from m.cpp:3:0: 
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’ 
    class tuple_element; 
     ^
m.cpp: In function ‘int main()’: 
m.cpp:16:30: error: ‘void v1’ has incomplete type 
    auto v1 = make_vector(1,2,3); 

Wie kann ich eine generische Routine machen,
, die den ersten Typ des ersten Parameters verwendet den Vektor zu instanziiert?
Wie kann ich die Argumente als Initializer-Werte an den Vektor weiterleiten?

+1

'#einschließen '? – Pixelchemist

+0

@Pixelchemist wow ... das ist genau richtig. Vielen Dank –

Antwort

1

Genau wie Sie es getan haben - sowohl gcc und msvc kompilieren Sie Ihre Funktion mit einem winzigen #include <tuple>.

6

Da Sie diese nicht verwenden können, sowieso einen leeren Vektor zu erstellen, können wir die tuple Abhängigkeit von nur Bereitstellung eines zusätzlichen Template-Argument vermeiden:

template <class T0, class... Ts> 
auto make_vector(T0&& first, Ts&&... args) 
{ 
    using first_type = std::decay_t<T0>; 
    return std::vector<first_type>{ 
     std::forward<T0>(first), 
     std::forward<Ts>(args)... 
    }; 
} 

die Arbeits den zusätzlichen Vorteil hat, wenn first bestanden habe als ein Wert.

2

Folgen Sie make_array 's führen, und ermöglichen Sie Benutzern, entweder einen Rückgabetyp explizit anzugeben, oder verwenden Sie einen Rückgabetyp von bestimmt.

Die Verwendung der perfekten Weiterleitung schlägt vor, dass Sie unnötiges Kopieren vermeiden möchten; das ist nicht konsistent mit dem initalizer_list Konstruktor, der eine Kopie jedes Elements benötigt. Also stattdessen den obigen Code reserve s die richtige Menge an Speicherplatz und dann emplace_back s die Elemente eins nach dem anderen mit dem üblichen Pack Expansion Trick. Ich habe den überladenen Komma-Schutz weggelassen, da vector::emplace_back dafür bekannt ist, void zurückzugeben.

push_back kann stattdessen verwendet werden, wenn Sie keine expliziten Konvertierungen auf Kosten einer möglichen Verschiebung bei einem Typenkonflikt aktivieren möchten. In diesem Fall wird der Typ jedoch entweder explizit vom Benutzer angegeben oder über implizite Konvertierungen von common_type abgeleitet, so dass emplace_back möglicherweise in Ordnung ist.