Czipperz
Czipperz

Reputation: 3336

Ensure return type of templated generic parameter

I'm trying to make a compile time generics example. I've made it enforce that the methods exists, but I can't figure out how to enforce the return type:

#include <type_traits>
template<class...> struct voider { using type = void; }
template<class... T> using void_t = typename voider<T...>::type;

template<class T, class = void> struct add_able : std::false_type {};
template<class T> struct add_able
< T, void_t < std::is_same < decltype(std::declval<T>().addOne()), void >,
              std::is_same < decltype(std::declval<T>().subOne()), void > > >
: std::true_type {};

class A { public: int addOne(); void subOne(); } // compiles and runs
class B { public: void addOne(int); void subOne(); } // fails
class C { public: void addOne(); void subOne(); } // compiles and runs as expected
class D { public: void subOne(); } // fails

This ensures that there is a addOne() and subOne() method but the return types are completely arbitrary. How do I enforce this?

Upvotes: 3

Views: 149

Answers (1)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48527

std::is_same<T> is a type. Its instantiation will never fail (triggering a substitution failure) as you'd expect. You have to wrap it in a std::enable_if and read the value that std::is_same<T> returns by accessing a nested ::value static member.

template<class T, class = void> struct add_able : std::false_type {};
template<class T> struct add_able
< T, void_t < typename std::enable_if<
//                     ~~~~~~~~~~~~~^
           std::is_same < decltype(std::declval<T&>().addOne()), void >::value
//                                                                     ~~~~~~^
           && std::is_same < decltype(std::declval<T&>().subOne()), void >::value
//        ~^^~                                                            ~~~~~~^
              >::type
//             ~~~~~^
            >
>
: std::true_type {};

DEMO

Upvotes: 3

Related Questions