【发布时间】:2018-06-28 06:49:53
【问题描述】:
我正在尝试注册这样的事件:
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 类型的integral constants 中似乎几乎相同(如true_type 和false_type)
所以,我想知道我是否在某处遗漏了类型名,或者为什么编译器无法将 type 识别为类型。
此外,必须有一种不太复杂的方法来执行此操作。我几乎可以肯定我只是没有看到它。如果有的话,谁能给我一个使用其他方法的类似案例的例子吗?
【问题讨论】:
-
Event::Resize不是类型,它是Event类型的值,即您在registerEvent中使用的Type,因此它永远无法匹配validate_event<Event::Resize, ...>跨度> -
validate_event<Event::Resize, ...>的唯一出现是template<Event, typename...> struct validate_event...的规范,仅当Event为Event::Resize时才会调用。您可以为专业化添加值 -
好的,所以
Type应该是Event::Resize...但是type是什么?您在registerEvent签名中使用Type作为类型,但它不是,它是一个值。当Type是一个值时,Type type没有任何意义。 -
你需要采用
register<Event::Resize>(callback)语法才能做你想做的事。 -
删除
Type type应该可以,编译器可以很容易地从函数指针中推断出Args
标签: c++ c++11 templates c++14 sfinae