Forced compile-time error in specialization

Recently, I began to study modern metaprogramming of templates, and I wrote myself an index_of function for types.

template<std::size_t Index, class C, class A> struct mp_index_of_impl{}; template<std::size_t Index, class C,template<class...> class A,class ...Ts> struct mp_index_of_impl<Index,C,A<C,Ts...>>{ using type = std::integral_constant<std::size_t,Index>; }; template<std::size_t Index, class C,template<class...> class A,class ...Ts,class T1> struct mp_index_of_impl<Index,C,A<T1,Ts...>>{ using type = typename mp_index_of_impl<Index + 1,C,A<Ts...>>::type; }; template<std::size_t Index, class C,template<class...> class A> struct mp_index_of_impl<Index,C,A<>>{ //static_assert(false,"Does not contain type"); using type = std::integral_constant<std::size_t,0>; }; 

The problem is my last specialization

 template<std::size_t Index, class C,template<class...> class A> struct mp_index_of_impl<Index,C,A<>>{ //throw a compile error here }; 

I tried using static_assert similar to this

 template<std::size_t Index, class C,template<class...> class A> struct mp_index_of_impl<Index,C,A<>>{ static_assert(false,"Does not contain type"); }; 

But this will cause a compilation error every time, even if it does not match.

I want to throw a compilation error with a special error message if this template specification is matched. How can I do it?

+5
source share
2 answers

If you put static_assert(false,...) in the template specialization, it is always impossible to create a valid code from it. It is poorly formed, no diagnostics are required.

The workaround for this is to have your static_assert dependent on the template parameter:

 template<typename T> struct assert_false : std::false_type { }; template <typename T> inline T getValue(AnObject&) { static_assert( assert_false<T>::value , "Does not contain type"); } 
+8
source

To get a really well-formed solution is a bit annoying. You work in [temp.res] / 8:

If the actual specialization cannot be generated for the template, and this template is not created, the template is poorly formed, it is not diagnosed ... If the hypothetical creation of the template immediately after its determination is poorly formed due to a design that does not depend on the template parameter, the program poorly formed; no diagnostics required.

So, we need to avoid everything that static_assert(false, ...) could do. In this case, we have a partial discovery. We could specialize in the case where we have only one type left, and say that this is what we are looking for:

 template<std::size_t Index, class C,template<class...> class A, class Last> struct mp_index_of_impl<Index,C,A<Last>>{ static_assert(std::is_same<C, Last>::value,"Does not contain type"); using type = std::integral_constant<std::size_t, Index>; }; 

This will not handle empty lists, but for this at the top level you can add another static_assert for non- static_assert :

 template<std::size_t Index, class C,template<class...> class A> struct mp_index_of_impl<Index,C,A<>>{ }; template <typename T> is_empty : std::false_type { }; template <template <class...> class A> is_empty<A<>> : std::true_type { }; template <class C, class X> struct mp_index_of : mp_index_of_impl<0, C, X> { static_assert(!is_empty<X>::value, "Does not contain type"); }; 

Although in practice, the TartanLlama solution is likely to get you from each compiler, and I would probably just use it.

+2
source

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


All Articles