用于回调注册的 SFINAE



>我尝试使用此技巧注册回调(如果存在),请使用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;
}

但我得到

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

似乎无论如何都会实例化无效的模板。这是因为Callback是类模板的一部分,而不是注册例程吗?

SFINAE 失败,因为它依赖于周围的类类型参数。SFINAE 仅适用于推导的类型参数,这些参数是编译器试图根据调用找出的函数类型参数。

修复可能如下所示:

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

其中 SFINAE 基于 S,编译器将推导出来而不是显式获取。

另外,请注意,您的第二次重载应该需要has_not_member,而不是has_member。就像现在一样,即使成员存在,也将始终选择它,因为当等效于模板重载时,会选择非模板重载。

最新更新