2

I tried to use this trick to register callback if it exists check if member exists using enable_if:

template<class Callback>
class Foo
{
  public:
    Foo()
    {barEventRegister(has_member{});}
  private:

  struct has_not_member{};

  struct has_member:public has_not_member{};

  template<class X> struct cb_test
  {typedef int type;};

  template<typename cb_test<decltype(&Callback::barEvent)>::type=0>
  void barEventRegister(has_member)
  {
    //register callback for bar
  }

  void barEventRegister(has_member)
  {
    //do nothing
  }
};

struct MyCallback
{
};

int main()
{
  Foo<MyCallback> foo;
}

But I get

template<typename cb_test<decltype(&Callback::barEvent)>::type=0>
void barEventRegister(has_not_member)
error: 'barEvent' is not a member of 'MyCallback' 

It appears that the invalid template is instantiated anyways. Is that because Callback is part of the class template, and not the registration routine?

Community
  • 1
  • 1
user877329
  • 6,717
  • 8
  • 46
  • 88

1 Answers1

2

Your SFINAE fails because it relies on the surrounding class type parameter. SFINAE only works on deduced type arguments, which are function type arguments the compiler tries to figure out based on the call.

A fix could look like:

template<class S = Callback, typename cb_test<decltype(S::barEvent)>::type=0>
void barEventRegister(has_member)

where the SFINAE is based on S, which the compiler will deduce rather then get explicitly.

Also, note that your second overload should take a has_not_member, not has_member. As it is now, it will always be chosen, even if the member exists, since non-template overloads are chosen when equivalent to template ones.

Eran
  • 21,632
  • 6
  • 56
  • 89