Testing on types of parameters of a non-piggy template

I would like to write a template that can deconstruct a type into a template with non-type type template parameters along with its non-type arguments. For example, it will deconstruct Array<5> into template<int> Array and 5 , but it will work in the general case for any type of template parameters of a non-type type (integral types, pointers, member pointers, etc.).

First try using the template specialization:

 template<typename T> struct foo { enum { n = 1 }; }; template<int x> struct bar { enum { n = x }; }; template<typename T, template<T> class X, T x> struct foo< X<x> > { enum { n = x }; }; // here x must be of integral type, but that just for testing int main(int, char**) { return foo< bar<16> >::n; } 

Clang 3.1 says:

 test145.cpp:6:8: warning: class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used struct foo< X<x> > { enum { n = x }; }; ^~~~~~~~~~~ test145.cpp:5:19: note: non-deducible template parameter 'T' template<typename T, template<T> class X, T x> ^ 1 warning generated. 

Second attempt, with function template:

 template<typename T, T x> struct box { static constexpr T value() { return x; } }; template<typename T, template<T> class X, T x> box<T, x> foo(X<x>); template<int> struct asdf { }; int main(int, char**) { return decltype(foo(*(asdf<9>*)0))::value(); } 

Klang says:

 test150.cpp:12:41: error: no matching function for call to 'foo' int main(int, char**) { return decltype(foo(*(asdf<9>*)0))::value(); } ^~~ test150.cpp:8:11: note: candidate template ignored: couldn't infer template argument 'T' box<T, x> foo(X<x>); ^ 1 error generated. 

GCC 4.7 talks about such things.

Is this a fundamental limitation?

Bonus question: if so, is there any way to handle all the infinite possibilities in a finite amount of code, even if it is less simple and general code? (This makes pointers difficult, for example: for the same reason that you cannot write template<T> , I don't think you could write template<T*> .)

Please do not ask why I ask.

+6
source share
1 answer

This other question asks basically the same thing, but for template type parameters, and not for non-template template parameters: metaprogramming template: (trait for?), Dissecting the given template into types T <T2, T3N, T4, ...>

For type parameters, this is really easy. The code is as follows:

 #include <tuple> #include <vector> template <class T> struct explode; template <template <class... Args> class T, class... N> struct explode<T<N...>> { typedef T<N...> type; template <class... Args> using template_ = T<Args...>; template <int I> using type_parameter = typename std::tuple_element<I, std::tuple<N...>>::type; }; #if TESTING void test_harness() { typedef explode<std::vector<int>> exv; exv::template_<char> vchar; // The second parameter still has its default argument! exv::template_<exv::type_parameter<0>, exv::type_parameter<1>> vint; static_assert(std::is_same<exv::template_<char>, std::vector<char>>::value, ""); static_assert(std::is_same<decltype(vchar), std::vector<char>>::value, ""); static_assert(std::is_same<decltype(vint), std::vector<int>>::value, ""); static_assert(std::is_same<exv::type, std::vector<int>>::value, ""); static_assert(std::is_same<exv::type_parameter<0>, int>::value, ""); static_assert(std::is_same<exv::type_parameter<1>, std::allocator<int>>::value, ""); } #endif 

But for parameters other than type, I still do not understand if this is possible. You can start with similar code.

 template <class... ArgTypes, template <ArgTypes... Args> class T, ArgTypes... N> struct explode<T<N...>> { typedef T<N...> type; template <ArgTypes... Args> using template_ = T<Args...>; template <int I> using type_of_parameter = typename std::tuple_element<I, std::tuple<ArgTypes...>>::type; template <int I> struct nontype_parameter { static constexpr type_of_parameter<I> value() { return std::get<I>(std::tuple<ArgTypes...>(N...)); } }; }; 

};

but Clang (at least) does not accept it:

 test.cc:8:8: warning: class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used struct explode<T<N...>> ^~~~~~~~~~~~~~~~ test.cc:7:20: note: non-deducible template parameter 'ArgTypes' template <class... ArgTypes, template <ArgTypes... Args> class T, ArgTypes... N> ^ 

and even if you somehow got away with this problem, you still have to replace std::get with the constexpr manual encoding, since the standard std::get library is not constexpr for any reason.

+2
source

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


All Articles