Check for type declaration for SFINAE

I would like to use SFINAE to overload a function template based on whether the template argument declares a type T. Here is where I have been able so far:

struct C1 {
    using T = int;
};

struct C2 {
    using T = void; // but I would really like 
                    // to not require T at all
};

// For classes that declare T
template <class C>
void f(C &c, typename std::enable_if<!std::is_same<typename C::T, void>::value,
                                     int>::type = 0) {
    (void)c;
    std::cout << "With T" << std::endl;
}

// For classes that do not declare T (for now, T must be declared void)
template <class C>
void f(C &c, typename std::enable_if<std::is_same<typename C::T, void>::value,
                                     int>::type = 0) {
    (void)c;
    std::cout << "Without T" << std::endl;
}

int main() {
    C2 c;
    f(c);
    return 0;
}

How (if at all) can this decision be changed so that it is C2not necessary to declare Tat all? That is, I would like to have two overloads: one for classes that declare T, and one for classes that don't.

+4
source share
2 answers
#include <type_traits>

template <typename...>
struct voider { using type = void; };

template <typename... Ts>
using void_t = typename voider<Ts...>::type;

template <typename C, typename = void_t<>>
struct has_t : std::false_type {};

template <typename C>
struct has_t<C, void_t<typename C::T>> : std::true_type {};

template <typename C>
auto f(C& c)
    -> typename std::enable_if<has_t<C>::value>::type
{
}

template <typename C>
auto f(C& c)
    -> typename std::enable_if<!has_t<C>::value>::type
{
}

Demo

+4
source

You can make a type trait according to your needs:

template<typename Type, typename Enable=void>
struct has_t : std::false_type {};

template<typename Type>
struct has_t<Type, void_t<Type::T>> : std::true_type {};

void_t implemented as follows:

template<typename...>
struct voider {
    using type = void;
};

template<class... Ts> using void_t = typename voider<Ts...>::type;

This implementation is void_tguaranteed to work in C ++ 11.

:

template<typename C, typename std::enable_if<has_t<typename std::decay<C>::type>::value, int>::type = 0>
void f(C&& c) {
    // ... C::T exists
}

template<typename C, typename std::enable_if<!has_t<typename std::decay<C>::type>::value, int>::type = 0>
void f(C&& c) {
    // ... C::T doesn't exists
}

, . typedef C , C&, .

+4

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