Zugriff auf n-tes Element eines variadic tuple templates



  • Hallo zusammen,

    ich habe ein tuple template:

    #include <iostream>
    
    template<typename... Tail>
    class tuple{
    public:
    };
    
    template<typename Head, typename... Tail>
    class tuple<Head, Tail...> :public tuple<Tail...>{
    public:
            Head value;
            typedef tuple<Tail...> type;
    
            tuple(Head h, Tail... t) : tuple<Tail...>(t...), value(h){
            }
    };
    
    template<typename Head, typename... Tail>
    void print(tuple<Head, Tail...>& t){
            std::cout << t.value << ' ';
            print(static_cast<typename tuple<Head, Tail...>::type&>(t));
    
    }
    
    template<typename Head>
    void print(tuple<Head>& t){
            std::cout << t.value << std::endl;
    }
    
    int main(){
            tuple<int, double, char, int> t(1, 1.1, 'c', 2);
            print(t);
    }
    

    Wie kann ich am elegantesten z.B. (nur) den char des Tupels auslesen oder verändern?
    Also am liebsten hätte ich eine Art Index-Zugriff...
    Eine weitere Frage nebenbei: Ist das Vorgehen mit dem static_cast und dem rekursiven Aufruf so empfehlenswert oder wie macht man es sonst?

    Gruß,
    XSpille



  • TypeAt:

    template <int, typename...>
    struct TypeAt;
    
    template <int N, typename Head, typename... Tail>
    struct TypeAt<N, Head, Tail...>
    {
            typedef typename TypeAt<N - 1, Tail...>::type type;
    };
    
    template <typename Head, typename... Tail>
    struct TypeAt<0, Head, Tail...>
    {
            typedef Head type;
    };
    

    Dein static_cast ist m.M.n. durchaus okay, aber normalerweise erbt man mit private und bietet eine friend-Funktion zum Zugriff an.



  • Danke 314159265358979!!!

    Ich brauch zwar kein TypeAt, aber der Index sollte sich ähnlich verwirklichen lassen...

    Welchen Vorteil hat die private Vererbung?



  • Ich seh schon, das hab ich falsch verstanden. Du willst nicht den char als Typ, sondern du willst den char, der im Tuple ist 🤡

    privat, da niemand den value kennen muss. get ist doch außerdem viel schöner für den Anwender. 🙂

    Ich meld mich gleich mit einem get, das TypeAt verwendet. Muss mich da ein bisschen rumspielen.



  • So, es ist mir gelungen. Hier ist mein get 🤡

    template <int N>
    struct int_to_type {};
    
    template <typename Head, typename... Tail>
    Head& get(tuple<Head, Tail...>& tup, int_to_type<0>)
    {
    	return tup.value;
    }
    
    template <int N, typename Head, typename... Tail>
    typename TypeAt<N, Head, Tail...>::type& get(tuple<Head, Tail...>& tup, int_to_type<N>)
    {
    	return get(static_cast<tuple<Tail...>&>(tup), int_to_type<N - 1>());
    }
    
    template <int N, typename Head, typename... Tail>
    typename TypeAt<N, Head, Tail...>::type& get(tuple<Head, Tail...>& tup)
    {
    	return get(static_cast<tuple<Tail...>&>(tup), int_to_type<N - 1>());
    };
    

    Hier nochmal bei Ideone kompiliert: http://ideone.com/NPmNH



  • Falls es nicht nur ums Experimentieren geht: Es gibt std::tuple und std::get() aus dem Standardheader <tuple> . Tupel sind teilweise auch schon auf Compilern verfügbar, die keine Variadic Templates unterstützen.



  • Danke 314159265358979!!!
    Ich werd mir das jetzt nicht ankucken, damit ich es selbst noch versuchen kann 😉

    Nexus schrieb:

    Falls es nicht nur ums Experimentieren geht: Es gibt std::tuple und std::get() aus dem Standardheader <tuple> . Tupel sind teilweise auch schon auf Compilern verfügbar, die keine Variadic Templates unterstützen.

    Danke Nexus! Mir gehts ausschließlich ums Experimentieren 🙂



  • Nexus schrieb:

    Falls es nicht nur ums Experimentieren geht: Es gibt std::tuple und std::get() aus dem Standardheader <tuple> . Tupel sind teilweise auch schon auf Compilern verfügbar, die keine Variadic Templates unterstützen.

    Wenn ich jetzt eine Lösung mit std::tuple verwirklichen möchte, wie krieg ich in einem Template dann analog zum TypeAt von 314159265358979 den Typen der entsprechenden Position heraus?

    Klar kann ich in C++0x ein auto verwenden...
    Gibt es etwas Vorimplementiertes? Also eine eigene Lösung mit variadic templates würde ich wohl auch hinkriegen. Man soll ja das Rad nicht zweimal erfinden 🙄



  • XSpille schrieb:

    Gibt es etwas Vorimplementiertes?

    Hab es selbst gefunden:
    std::tuple_element

    Kurzes Beispiel:

    #include<iostream>
    #include<tuple>
    
    int main(){
            typedef std::tuple<int, char, double> tuple_type;
            tuple_type t(1, 'c', 1.1);
            typedef typename std::tuple_element<0,tuple_type>::type tuple_type1;
            typedef typename std::tuple_element<1,tuple_type>::type tuple_type2;
            typedef typename std::tuple_element<2,tuple_type>::type tuple_type3;
            tuple_type1& v1 = std::get<0>(t);
            tuple_type2& v2 = std::get<1>(t);
            tuple_type3& v3 = std::get<2>(t);
            v1 = 2;
            v2 = 'd';
            v3 = 1.2;
            std::cout << std::get<0>(t) << ' ' << std::get<1>(t) << ' ' << std::get<2>(t) << std::endl;
    }
    

    Danke trotzdem fürs Lesen...



  • XSpille schrieb:

    Wenn ich jetzt eine Lösung mit std::tuple verwirklichen möchte, wie krieg ich [...] den Typen der entsprechenden Position heraus?

    std::tuple_element , siehe z.B. MSDN-Dokumentation.

    Edit: Hm, etwas zu spät. Aber was mir noch aufgefallen ist, in deinem Code ist das typename falsch. Die Templates sind ja alle vollständig instanziiert, also sind keine abhängigen Typen mehr im Spiel. Generell kann typename sich nie ausserhalb eines Templates befinden.



  • Nexus schrieb:

    XSpille schrieb:

    Wenn ich jetzt eine Lösung mit std::tuple verwirklichen möchte, wie krieg ich [...] den Typen der entsprechenden Position heraus?

    std::tuple_element , siehe z.B. MSDN-Dokumentation.

    Danke dir!
    Ich hatte nichts gefunden und nachdem ich gepostet habe, dann quasi sofort 🙄


Anmelden zum Antworten