2

Say I have the two following test-classes:

struct TestYes {
    using type = void;
    template <typename... T>
    using test = void;
};

struct TestNo { };

and I want to determine if they have this template member test.

For the member type,

template <typename, typename = void>
struct has_type_impl {
    using type = std::false_type;
};
template <typename T>
struct has_type_impl<T, typename T::type> {
    using type = std::true_type;
};
template <typename T>
using has_type = typename has_type_impl<T>::type;

works perfectly:

static_assert( has_type<TestYes>::value, ""); // OK
static_assert(!has_type<TestNo>::value, "");  // OK

but the equivalent for the template member test:

template <typename, template <typename...> class = std::tuple>
struct has_test_impl {
    using type = std::false_type;
};
template <typename T>
struct has_test_impl<T, T::template test> {
    using type = std::true_type;
};
template <typename T>
using has_test = typename has_test_impl<T>::type;

fails on

static_assert( has_test<TestYes>::value, "");

I know I can use SFINAE like:

template <typename T>
struct has_test_impl {
private:
    using yes = std::true_type;
    using no = std::false_type;

    template <typename U, typename... Args>
    static auto foo(int) -> decltype(std::declval<typename U::template test<Args...>>(), yes());

    template <typename> static no foo(...);

public:
    using type = decltype(foo<T>(0));
};

template <typename T>
using has_test = typename has_test_impl<T>::type;

but I'm wondering why the compiler is correctly deducting the partial specialization of has_type_impl while it remains on the first definition of has_test_impl.

Thanks in advance for your enlightenment!

O'Neil
  • 3,790
  • 4
  • 16
  • 30
  • 1
    Change `TestYes::type` to `int` and your first test will break as well. This is essentially http://stackoverflow.com/questions/27687389/how-does-void-t-work – T.C. May 04 '15 at 03:52

1 Answers1

2
template<template<class...> class...>
using void_templ = void;

template <typename, typename = void>
struct has_test_impl {
    using type = std::false_type;
};
template <typename T>
struct has_test_impl<T, void_templ<T::template test>> {
    using type = std::true_type;
};
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thanks for your answer. Using version 4.9.2 of gcc, I met [this issue](http://stackoverflow.com/questions/25833356/is-there-a-compiler-bug-exposed-by-my-implementation-of-an-is-complete-type-trai/25833474#25833474) you should be familiar with ^^. Adapted for template template, it worked like a charm. Double thanks! :D – O'Neil May 04 '15 at 05:50