2015-10-02 6 views
3

Я пытаюсь создать пример обобщенных данных. Я сделал это в жизнь, что методы существуют, но я не могу понять, как обеспечить тип возвращаемого значения:Убедитесь, что тип возвращаемого шаблона с шаблоном

#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 

Это гарантирует, что существует addOne() и subOne() метод, но возвращаемые типы совершенно произвольны. Как это сделать?

ответ

3

std::is_same<T> - это тип. Его создание никогда не завершится неудачей (вызвав отказ замены), как вы ожидали. Вы должны обернуть его в std::enable_if и прочитать значение, которое возвращает std::is_same<T>, обратившись к вложенному статическому члену ::value.

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

+0

Он работает возгласы ликования! – Czipperz

+0

@Czipperz вы можете сократить синтаксис с помощью 'std :: is_void' вместо' std :: is_same <..., void> ' –

+0

Nice. Обратите внимание, что это также работает без void_t: http://coliru.stacked-crooked.com/a/bd41f8a2c7b4bea2 –