Detect same class inheritance with SFINAE

c++, c++11, decltype, sfinae, template-meta-programming

Solution

You can't catch duplicate inheritance with SFINAE, because it is not one of the listed reasons for deduction to fail under 14.8.2p8 [temp.deduct]; equally, it is because the error occurs outside the "immediate context" of template deduction, as it is an error with the instantiation of your `struct fail`.

There is however a very similar technique which is suitable for use in your case, which is to detect an ambiguous conversion from a derived class to multiple base classes. Clearly the ambiguous base classes can't be inherited directly from a single derived class, but it works fine to inherit them in a linear chain:

C<> A<int>
|  /
C<int> A<char>
|     /
C<char, int> A<int>
|           /
C<int, char, int>

Now a conversion from `C<int, char, int>` to `A<int>` will be ambiguous, and as ambiguous conversion is listed under 14.8.2p8 we can use SFINAE to detect it:

#include <type_traits>

template<class> struct A {};
template<class... Ts> struct C;
template<> struct C<> {};
template<class T, class... Ts> struct C<T, Ts...>: A<T>, C<Ts...> {};
template<class... Ts> void f(A<Ts>...);
template<class... Ts> std::false_type g(...);
template<class... Ts> decltype(f((A<Ts>(), C<Ts...>())...), std::true_type()) g(int);
template<class... Ts> using distinct = decltype(g<Ts...>(0));

static_assert(distinct<int, char, float>::value, "!!");
static_assert(!distinct<int, char, int>::value, "!!");

Problem

I'm trying to write a metafunction that checks whether all types passed as a variadic template parameter are distinct. It seems that the most performant way to do this is to inherit from a set of classes and detect, whether there is an error. The problem is that compilation fails in the following code, while I would expect SFINAE to work. Edit. The question is not "how to write that metafunction" but "how do I catch that double inheritance error and output `false_type` when it happens". AFAIK, it's possible only with SFINAE. ``` template <typename T> struct dummy {}; // error: duplicate base type ‘dummy<int>’ invalid template <typename T, typename U> struct fail : dummy<T>, dummy<U> {}; template <typename T> true_type test(fail<T, T> a = fail<T, T>()); false_type test(...); int main() { cout << decltype(test<int>())::value << endl; } ``` Live version here. Edit. Previously I've tried to do this with specialization failure, but it didn't work either with the same compilation error. ``` template <typename T> struct dummy {}; template <typename T, typename U> struct fail : dummy<T>, dummy<U>, true_type {}; template <typename T, typename U = void> struct test : false_type {}; template <typename T> struct test<T, typename enable_if<fail<T, T>::value, void>::type> : true_type {}; ``` Live version here.

Original source

Related problems