Variadic Templates and Alexandrescu tuple Implementation

I'm trying to learn a little about metaprogramming patterns and I'm currently playing with variable patterns.

In his presentation, “Variadic Templates - Fandaki”, Alexandrescu presents an implementation of a small tuple, which I am trying to build and possibly expand a bit. (I know this is a toy example, I'm just trying to learn a little bit more about C ++). However, I have a little problem with its code.

There he is:

template <typename... Ts> class tuple {}; template<size_t, typename> struct tuple_element; template<typename T, typename... Ts> struct tuple_element<0, tuple<T, Ts...>> { typedef T type; }; template <size_t k, typename T, typename... Ts> struct tuple_element<k, tuple<T, Ts...>> { typedef typename tuple_element<k-1,tuple<Ts...>>::type type; }; template<size_t k, typename... Ts> typename std::enable_if<k == 0, typename tuple_element<0,tuple<Ts...>>::type&>::type get(tuple<Ts...>& t) {return t.head_;} template<size_t k, typename T, typename... Ts> typename std::enable_if<k != 0, typename tuple_element<k,tuple<T,Ts...>>::type&>::type get(tuple<T,Ts...>& t) { tuple<Ts...> & super = t; return get<k-1>(super); } template <typename T, typename... Ts> class tuple<T,Ts...> : private tuple<Ts...> { private: T head_; }; int main(int argc, char *argv[]) { tuple<int,std::string> t; get<0>(t) = 10; get<1>(t) = std::string("test"); std::cout<<get<0>(t)<<std::endl; } 

In order to work correctly, the get function must be (this is also mentioned on this slide, see 32). But what does a friend’s announcement look like? I tried different approaches but could not get it to work. When I change the code from private to public inheritance and change the access rules for head_ for the public, it works.

thanks for the help

Kevin

+5
source share
2 answers

This works for me:

 template <typename T, typename... Ts> class tuple<T,Ts...> : private tuple<Ts...> { private: T head_; template<size_t k, typename T1, typename... T1s> friend typename std::enable_if<k != 0, typename tuple_element<k,tuple<T1,T1s...>>::type&>::type get(tuple<T1,T1s...>& t); template<size_t k, typename... T1s> friend typename std::enable_if<k == 0, typename tuple_element<0,tuple<T1s...>>::type&>::type get(tuple<T1s...>& t); }; 

Demo

+4
source

Another implementation from a different perspective:

 #include <iostream> #include <type_traits> template <class... Args> class Tuple; template <> class Tuple<> {}; template <class T, class... Args> class Tuple<T, Args...>: public Tuple<Args...> { using Base = Tuple<Args...>; T Value_; public: Tuple(T&& value, Args&&... args) : Value_(std::forward<T>(value)) , Base(std::forward<Args>(args)...) { } T& Value() { return Value_; } }; template <size_t k, class T, class... Args> struct Select { using Type = typename Select<k - 1, Args...>::Type; }; template <class T, class... Args> struct Select<0, T, Args...> { using Type = T; }; template <size_t k, class... Args> using TSelect = typename Select<k, Args...>::Type; template <bool P, class T> using TEnableIf = typename std::enable_if<P, T>::type; template <size_t k, class T, class... Args> TEnableIf<(k != 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) { return get<k - 1, Args...>(t); } template <size_t k, class T, class... Args> TEnableIf<(k == 0), TSelect<k, T, Args...>&> get(Tuple<T, Args...>& t) { return t.Value(); } int main() { Tuple<int, char> t(1, 'a'); std::cout << get<0>(t) << std::endl; std::cout << get<1>(t) << std::endl; get<1>(t) = 'b'; std::cout << get<1>(t) << std::endl; } 

In fact, we do not need Tuple to get a type.

0
source

Source: https://habr.com/ru/post/1202494/


All Articles