对于枚举,替换失败不是错误(SFINAE)

xos*_*tom 3 c++ traits 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
};
Run Code Online (Sandbox Code Playgroud)

然后,Do<B>();工作和Do<A>();失败.但是,当iOption不存在时,我可以提供默认行为.所以我将Do to 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> >();
};
Run Code Online (Sandbox Code Playgroud)

现在,缺少的部分是DoesOptionExist<T>- 检查结构中是否存在iOption的方法.当然SFINAE适用于函数名称或函数签名,但不确定它是否适用于枚举值.

Xeo*_*Xeo 6

如果你可以使用C++ 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);
};
Run Code Online (Sandbox Code Playgroud)

C++ 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);
};
Run Code Online (Sandbox Code Playgroud)

用法:

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
}
Run Code Online (Sandbox Code Playgroud)