Variational Templates - Incomplete Type

The presence of this code:

template<class ...Args> struct Are_Same { enum {value = Are_Same<Args...>::value}; }; template<class A,class... C> struct Are_Same<A,C...> { enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE }; template<class A,class B> struct Are_Same<A,B> { enum {value = std::is_same<A,B>::value}; }; 

I get an error from gcc 4.6.1:

error: incomplete type 'Are_Same' used in the nested name specifier.

I thought that by executing Are_Same<A,C...>::value , I would call a recursive call, which at the end would just expand to Are_Same<A,B> . Obviously, this is not so. Does anyone know where I am going wrong?

+7
source share
3 answers

I think the template definitions are wrong, in both cases you invoke exact recursion. I would expect the compiler to die with some stackoverflow inside the compiler, but another error occurs ...

The implementation of the are_same variational template can be:

 template <class... Args> // base (optional to declare the template) struct are_same; template <class A, class B, class... Args> // recursion struct are_same<A,B,Args...> { static const bool value = is_same<A,B>::value && are_same<A,Args...>::value; }; template <class A, class B> // stop condition struct are_same<A,B> { static const bool value = is_same<A,B>::value; }; 

Note that in the recursion step recursion one argument is removed from the argument list, so a new problem to solve is a smaller version of the original. This type of metaprogramming of templates is quite related to recursion, and the same rules apply to be able to use the recursion necessary so that each recursive step brings you closer to the solution. In this particular case, given a list of N possible identical types, each step reduces the problem to determine if the N-1 types are the same.

You can use alternatively, as a stop condition (replacing the former), a degenerate version of the are_same problem:

 template <class A> struct are_same<A> { static const bool value = true; }; 

Which is degenerate in the sense that there really is no point in asking if one type is * is_same *, but it might be appropriate for different metaprogramming tasks.

Another potentially more efficient algorithm (I'm not sure that the compiler will avoid creating a template in the previous recursion step), which is not dependent on is_same , might be:

 template <class... Args> struct are_same; template <class A, class... Args> struct are_same<A,A,Args...> { // recursion static const bool value = are_same<A,Args...>::value; }; template <class A, class B, class... Args> struct are_same<A,B,Args...> { // cut, A and B are not the same static const bool value = false; }; template <class A> struct are_same<A> { // end of recursion static const bool value = true; }; 

In this case, the compiler will prefer recursion for cut steps whenever the two types are the same, so we do not need to check is_same internally. At the same time, if the compiler goes to the cut step, we do not need to process the rest of the type list, as we already know the answer.

+8
source

I would do it like this:

 #include <type_traits> #include <iostream> template <class... Args> struct are_same { static const bool value=true; }; template <class A, class B, class... Args> // recursion struct are_same<A,B,Args...> { static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value; }; int main() { std::cout<< std::boolalpha << are_same< int >::value << std::endl; std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl; std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl; } 
+3
source

Probably the simplest implementation might be this:

 template <typename... TList> struct are_same { constexpr static bool value = false; }; template <typename T, typename... TList> struct are_same<T, T, TList...> { constexpr static bool value = are_same<T, TList...>::value; }; template <typename T> struct are_same<T> { constexpr static bool value = true; }; 

Alternatively, you can replace the break condition with

 template <typename T> struct are_same<T, T> { constexpr static bool value = true; }; 

But the first one is more general, because are_same<type>::value == true . Another question is what should are_same<>::value equal. This gives you false , but you should not add another specialized specialization.

 template <> struct are_same<> { constexpr static bool value = true; }; 
0
source

All Articles