我正在尝试注册这样的事件:
void myResize(unsigned int width, unsigned int height);
int main() {
registerEvent(Event::Resize, myResize);
}
首先,我尝试为每个事件创建一个重载,但后来我意识到如果有两个事件具有相同的参数,这将不起作用,所以我尝试使用模板和 SFINAE。
在网上冲浪几个小时后,我开始对它们有最低限度的了解。
这是我的最后一种方法:
#include <type_traits>
enum class Event { Resize };
template<typename T>
struct enabler { typedef void type; };
template<Event, typename...>
struct validate_event : std::false_type {};
template<Event Evt, typename T>
struct validate_event<Evt, T> : std::false_type {};
template<> //This is the only case when registerEvent should be validated
struct validate_event<Event::Resize, unsigned int, unsigned int> : std::true_type {};
template<Event Type, typename ...Args>
typename enabler<
typename std::enable_if <
validate_event<Type, Args...>::value // <-- Error Here
> ::type
> ::type
registerEvent(Type type, void (*f)(Args...));
这种方法抛出几个语法错误(因为"此处的错误"标记行并遍历整个堆栈跟踪),以及一个警告,告诉:
'validate_event<__formal,<unnamed-symbol>...>::value': dependent name is not a type
.
在互联网上查找警告后,似乎是因为类型未定义为typename
。
也尝试使用value
而不是type
,因为它们在 bool 类型的整数常数中似乎几乎相同(如 true_type 和 false_type)
所以,我想知道我是否在某处缺少类型名,或者为什么编译器无法将type
识别为类型。
此外,必须有一种不太复杂的方法来做到这一点。我几乎可以肯定我只是没有看到它。如果有的话,谁能给我一个使用其他方法的类似案例的例子?
我看不出在这里enable_if
的意义(而且您的enabler
没有做任何有用的事情)。只需使用专用化将事件类型映射到所需的函数指针签名,并直接将其用作参数类型:
template<Event> struct event_fn;
template<> struct event_fn<Event::Resize> {
using type = void (*)(unsigned, unsigned);
};
// other specializations
// alias template shorthand
template<Event Type> using event_fn_t = typename event_fn<Type>::type;
template<Event Type>
void registerEvent(event_fn_t<Type> f);
与您的方法(修复后)相比,这在处理重载集时更干净:因为只有一个目标类型,编译器可以选择正确的重载,而无需手动消除歧义:
void foo(unsigned, unsigned);
void foo();
registerEvent<Event::Resize>(foo); // OK with the above but not with the original