Ошибка замены не является ошибкой (SFINAE) для перечисления

Есть ли способ использовать сбой замены не является ошибкой (SFINAE) для перечисления?

template <typename T>
struct Traits
{
}
template <>
struct Traits<A>
{
};
template <>
struct Traits<B>
{
  enum
  {
     iOption = 1
  };
};

template <T>
void Do()
{
  // use Traits<T>::iOption
};

Затем Do<B>(); работает, а Do<A>(); не работает. Однако я могу указать поведение по умолчанию, когда iOption не существует. Поэтому я отделяю часть Do от DoOption.

template <typename T, bool bOptionExist>
void DoOption()
{
  // can't use Traits<T>::iOption. do some default behavior 
};
template <typename T>
void DoOption<T, true>()
{ 
  // use Traits<T>::iOption
};
template <T>
void Do()
{
  // 'Do' does not use Traits<T>::iOption. Such codes are delegated to DoOption.
  DoOption<T, DoesOptionExist<T> >();
};

Теперь недостающая часть — это DoesOptionExist<T> — способ проверить, существует ли iOption в структуре. Конечно, SFINAE работает для имени функции или сигнатуры функции, но не уверен, что это работает для значения перечисления.


person xosp7tom    schedule 21.12.2011    source источник
comment
Обратите внимание, что мы восстановили этот вопрос, потому что я только что закончил писать свой ответ, когда вы его удалили. :)   -  person Xeo    schedule 22.12.2011
comment
Чего именно вы надеетесь достичь?   -  person Karl Knechtel    schedule 22.12.2011


Ответы (1)


Если вы можете использовать С++ 11, это совершенно тривиально:

template<class T>
struct has_nested_option{
  typedef char yes;
  typedef yes (&no)[2];

  template<class U>
  static yes test(decltype(U::option)*);
  template<class U>
  static no  test(...);

  static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};

Версия С++ 03 (на удивление) похожа:

template<class T>
struct has_nested_option{
  typedef char yes;
  typedef yes (&no)[2];

  template<int>
  struct test2;

  template<class U>
  static yes test(test2<U::option>*);
  template<class U>
  static no  test(...);

  static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};

Использование:

struct foo{
  enum { option = 1 };
};

struct bar{};

#include <type_traits>

template<class T>
typename std::enable_if<
  has_nested_option<T>::value
>::type Do(){
}

int main(){
  Do<foo>();
  Do<bar>(); // error here, since you provided no other viable overload
}
person Xeo    schedule 21.12.2011
comment
Я удалил, так как обнаружил, что на этот вопрос уже ответили другие сообщения. Тем не менее, ответ С++ 11 выглядит красиво. - person xosp7tom; 23.12.2011