2013-05-15 3 views
10

Angenommen, ich ein Tupel habenEin std-Tupel in Zeiger entpacken?

std::tuple<A, B, C> myFavoriteTuple; 

kann ich dies tun:

A a; 
B b; 
C c; 
std::tie(a, b, c) = myFavoriteTuple 

Aber wenn einige dieser Tupel wirklich teuer zu kopieren, was ich wirklich möchte eine Referenz nehmen oder ein Zeiger auf die richtigen Stellen in meinem Tupel. Ich kann dies tun:

A* a = &std::get<0>(myFavoriteTuple); 
B* b = &std::get<1>(myFavoriteTuple); 
C* c = &std::get<2>(myFavoriteTuple); 

Aber das scheint so lahm im Vergleich zu, wie genial die tie Syntax ist. Gibt es eine andere Möglichkeit, Zeiger/Referenzen auf die Tupel-Komponenten zu bekommen?

+0

Siehe Boost.Fusion –

+3

Das Verschieben von Tupel könnte in einigen Fällen die beste Idee sein - 'std :: tie (a, b, c) = std :: move (meinFavoritentuple);' – zch

+0

Oh Mann, C++ 17 ist großartig: 'auto && [a, b, c] = meinFavoritTuple;' fertig. – Barry

Antwort

5

die üblichen Indizes Infrastruktur Gegeben:

template<int... Is> 
struct seq { }; 

template<int N, int... Is> 
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { }; 

template<int... Is> 
struct gen_seq<0, Is...> : seq<Is...> { }; 

Sie eine Funktion erstellen können, die ein Tupel von Zeiger zurückgibt, wobei jedes Element ein Zeiger auf das entsprechende Element des Eingangstupel sein:

template<typename... Args, int... Is> 
auto make_pointer_tuple(std::tuple<Args...>& t, seq<Is...>) 
    -> std::tuple<typename std::add_pointer<Args>::type...> 
{ 
    return std::make_tuple(&std::get<Is>(t)...); 
} 

template<typename... Args> 
auto make_pointer_tuple(std::tuple<Args...>& t) 
    -> std::tuple<typename std::add_pointer<Args>::type...> 
{ 
    return make_pointer_tuple(t, gen_seq<sizeof...(Args)>()); 
} 

Und das ist, wie Sie es verwenden könnten:

std::tuple<int, bool, std::string> myFavoriteTuple{0, false, ""}; 

int* pInt = nullptr; 
bool* pBool = nullptr; 
std::string* pString = nullptr; 
tie(pInt, pBool, pString) = make_pointer_tuple(myFavoriteTuple); 

Hier ist eine live example.

+1

@Barry: Ja, oft sind die Template-Typen beschäftigt, in der Lounge zu chatten, also bin ich frei, langsam hereinzuschleichen und zu antworten;) –

+0

Fragen Sie sich, ob dieser Vorschlag es besser machen würde? http://open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html – balki

+0

@balki: Yep, das wird die Indizes Maschinen standardisieren –

0

Was ist mit den folgenden?

template<typename T> 
struct ptie 
{ 
    const T *ptr; 
    ptie() 
     :ptr(nullptr) 
    {} 

    void operator=(const T &x) 
    { 
     ptr = &x; 
    } 
}; 

ptie<A> a; 
ptie<B> b; 
ptie<C> c; 
std::tie(a, b, c) = myFavoriteTuple; 

Dann können Sie *a.ptr verwenden das Objekt zuzugreifen. Sie können sogar operator-> usw. überschreiben, wenn Ihnen danach ist.

Der Hauptnachteil dieser Methode ist, dass es die Tupel-Mitglieder als const wegen der operator=(const T&) binden. Sie könnten es mit ptr = const_cast<T*>(x) entfernen, aber ich denke, das könnte die const-Korrektheit in einigen Fällen brechen.