>我尝试使用此技巧注册回调(如果存在),请使用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
。就像现在一样,即使成员存在,也将始终选择它,因为当等效于模板重载时,会选择非模板重载。