Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Substitution failure is not an error (SFINAE) for enum

Tags:

c++

sfinae

traits

Is there a way to use Substitution failure is not an error (SFINAE) for enum?

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

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

Then, Do<B>(); works and Do<A>(); fails. However, I can supply a default behavior when iOption does not exist. So I separate out some part of 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> >();
};

Now, the missing piece is DoesOptionExist<T> - a way to check whether iOption exists in the struct. Certainly SFINAE works for function name or function signature, but not sure it works for enum value.

like image 462
xosp7tom Avatar asked Jan 22 '26 01:01

xosp7tom


1 Answers

If you can use C++11, this is completely trivial:

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);
};

The C++03 version is (surprisingly) similar:

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);
};

Usage:

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
}
like image 62
Xeo Avatar answered Jan 24 '26 19:01

Xeo