Disable functions inside the template

I am trying to disable some functions inside a simple template class. The functions to be deleted depend on whether the template argument has a specific typedef.

An example is as follows:

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}

However, this gives me a style error error: no type named ‘Nested’ in ‘struct NoNested’for gcc and clang ++ (remember the old versions of both).

Is there an easy way to remove foowhen typedef T::Nestedfails? (In addition to the template specialization of the class Foo<T>, as in real code, I have this for about 5 functions with different typedefs .., which will lead to 2 ^ 5 different specializations)

EDIT: Since some of them ask for motivation to want to do this: I would like to create something like FSM for use in DSL.

I would like to be able to do this

struct StateA;
struct StateB;
struct StateC;

struct StateA
{
  typedef StateB AfterNext;
};

struct StateB
{
   typedef StateA AfterPrev;
   typedef StateC AfterNext;
};

struct StateC
{
   typedef StateB AfterPrev;
};

template<typename T>
struct FSM
{
   FSM<typename T::AfterNext> next() { return FSM<T::AfterNext>(); };
   FSM<typename T::AfterPrev> prev() { return FSM<T::AfterPrev>(); };
};

So,

FSM<StateA>().next().prev().next().next();

,

FSM<StateA>().next().prev().prev();

.

, , , - , FSM - .

UPDATE: , , . , - , , , ( ), ( ) - , .

+5
5

. , .

+4

foo. , , NoNested.

+1

typedef , .

struct null_type;  //an incomplete type, you could use a more descriptive name for your particular problem

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
   typedef null_type Nested;
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();  //attempt to use incomplete type when used
  fnn.bar();
}
+1

T::Nested, , void, .

void:

template<class T, class = void>
struct NestedReturn
{
  typedef void type;
};

, void, , :

template<class T>
struct Void
{
  typedef void type;
};

Nested SFINAE. , typename Void<typename T::Nested>::type , void :

template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
  typedef typename T::Nested type;
};

. , foo() , T::Nested, .

template<typename T>
struct Foo
{
  typename NestedReturn<T>::type foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}

, foo() SFINAE, ++ 11 ( ):

template<typename T>
struct Foo
{
  template<class N = T::Nested>
  N foo() { return N(); }
  int bar() { return 1; }
};
+1

, . 763305. 2 * N , 2 ^ N.

template <typename T>
struct has_nested {
  // Variables "yes" and "no" are guaranteed to have different sizes,
  // specifically sizeof(yes) == 1 and sizeof(no) == 2.
  typedef char yes[1];
  typedef char no[2];

  template <typename C>
    static yes& test(typename C::Nested*);

  template <typename>
    static no& test(...);

  // If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
  // the first overload worked and T has a nested type named type.
  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};



template<typename T>
struct FooBase
{
  int bar() { return 1; }
};

template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};

template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
  typename T::Nested foo() { return typename T::Nested(); }
};


template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();

}
0

All Articles