How to create a recursive data structure for variable templates?

I am trying to understand the technique of generating a recursive data structure using TMP with this question.

Question

Suppose I have a variation template template<typename... Ts> struct my_sets { }; .

In my_sets I would like to generate a new type whose members depend on Ts .

For example, I want my_sets have one std::set<T> data element for each element / type that is in Ts...

 using x_t = my_sets<int,char,std::string>; x_t x; x.insert<0>( 5 ); // into a std::set<int> member in my_sets<> x.insert<1>( 'z' ); // into a std::set<char> member in my_sets<> x.insert<2>( "foo" ); // into a std::set<std::string> member in my_sets<> 

I think one way to achieve this might be to use subclass and recursion, but I'm not sure.

fwiw, if you implement the mutator more directly through a free function or overloading a simple function, this is also normal:

 insert<0>( x, 5 ); // into a std::set<int> member in my_sets<> insert<1>( x, 'z' ); // into a std::set<char> member in my_sets<> insert<2>( x, "foo" ); // into a std::set<std::string> member in my_sets<> 
+4
source share
2 answers

What happened to std::tuple here?

 #include <tuple> #include <set> template<class... Ts> using my_sets = std::tuple<std::set<Ts>...>; // ... auto x = my_sets<int, char, std::string>; std::get<0>(x).insert(5); std::get<1>(x).insert('z'); std::get<2>(x).insert("foo"); 

For appearance, add the free insert function:

 #include <utility> template<std::size_t I, class SetTuple, class Arg> auto insert(SetTuple& st, Arg&& arg) -> decltype(std::get<I>(st).insert(std::forward<Arg>(arg))) { return std::get<I>(st).insert(std::forward<Arg>(arg)); } 
+12
source

@Xeo has an elegant and simple solution. However, if you want to have insert<> as a member function, you can use the following approach:

 #include <set> #include <tuple> template<typename... Ts> struct my_sets : protected std::set<Ts>... { using types = std::tuple<Ts...>; template<int I, typename T> typename std::pair< typename std::set<typename std::tuple_element<I, types>::type>::iterator, bool> insert(T&& t) { return std::set<typename std::tuple_element<I, types>::type>::insert( std::forward<T>(t) ); } // ... // Function for retrieving each set... template<int I> typename std::set<typename std::tuple_element<I, types>::type>& get() { return *this; } }; 

And this is how you use it

 #include <string> int main() { my_sets<int, double, std::string> s; s.insert<0>(42); s.insert<1>(3.14); s.insert<2>("Hello World!"); s.get<0>().insert(42); } 

Note that the above solution does not allow multiple occurrences of the same type in the type list (which may or may not be desirable), although it can be fairly easily expanded to allow them:

 #include <set> #include <tuple> namespace detail { template<int... Is> struct indices { typedef indices<Is..., sizeof...(Is)> next; }; template<int I> struct index_range { using type = typename index_range<I - 1>::type::next; }; template<> struct index_range<0> { using type = indices<>; }; template<int I, typename T> struct dummy : T { }; template<typename, typename... Ts> struct my_sets { }; template<int... Is, typename... Ts> struct my_sets<indices<Is...>, Ts...> : protected dummy<Is, std::set<Ts>>... { using types = std::tuple<Ts...>; template<int I, typename T> typename std::pair< typename std::set<typename std::tuple_element<I, types>::type>::iterator, bool > insert(T&& t) { return dummy<I, std::set<typename std::tuple_element<I, types>::type>>:: insert(std::forward<T>(t)); } template<int I> dummy<I, std::set<typename std::tuple_element<I, types>::type>>& get() { return *this; } }; } template<typename... Ts> using my_sets = detail::my_sets< typename detail::index_range<sizeof...(Ts)>::type, Ts... >; 

And here is how you use it:

 #include <string> int main() { my_sets<int, double, int, std::string> s; s.insert<0>(42); s.insert<1>(3.14); s.insert<2>(1729); s.insert<3>("Hello World!"); s.get<0>().insert(42); } 
+2
source

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


All Articles