无法推导可变模板的模板类型
Could not deduce template type for variadic template
本文关键字:类型 更新时间:2023-10-16
我创建了一个简单的基于回调的事件管理器,它可以工作,但我有一些零模板参数的错误。
class event_manager
{
public:
template <typename... T>
static void register_event(const unsigned long e, std::function<void(T...)> ec)
{
events.insert({ e, ec });
}
template <typename... T>
static void fire_event(const unsigned long e, T... args)
{
for (auto it : events)
{
if (it.first == e)
{
boost::any_cast<std::function<void(T...)>>(it.second)(args...);
}
}
}
private:
static std::unordered_multimap<unsigned int, boost::any> events;
};
我用这段代码添加回调:
event_manager::register_event<unsigned int>(DVU_EVENT_KEY_PRESSED, [](unsigned int key)
{
//Works!
});
event_manager::register_event(DVU_EVENT_IDLE, []()
{
//Could not deduce template argument
});
第二个问题:是否可以更改代码以删除类似<unsigned int>
的模板规范?
示例:
event_manager::register_event(DVU_EVENT_KEY_PRESSED, [](unsigned int key){}));
由于lambda只是一个具有operator()
的函子,因此可能会有一个重载来推导它:
template <typename F>
static void register_event(const unsigned long e, F f)
{
register_event(e, f, &F::operator());
}
template <typename F, typename R, typename... T>
static void register_event(const unsigned long e, F& f,
R (F::*method)(T...) const)
{
std::function<R(T...)> func = f;
events.insert({ e, func });
}
可能需要R == void
或static_assert
之类的。
即使是第一个也不会像您一样在这里编译。
std::function
与lambda不完全匹配,并且当您使用变参数模板时,您不能以这种方式指定所有类型(因为您指定了第一个类型,编译器可能会推导出其余类型)。
一个可能的解决方法是只通过函数
template <typename Func>
static void register_event(const unsigned long e, Func ec);
并用Func::operator()
您的设计是不安全的,因为依赖类型推导来生成完全匹配的类型是脆弱的,并且您的类型转换需要完全匹配的型号。
这里有一个略有不同的设计:
class event_manager {
public:
template <typename Signature>
static void register_event(const unsigned long e, std::function<Signature> ec) {
events.emplace( e, std::move(ec) );
}
template <typename Signature, typename...Ts>
static void fire_event(const unsigned long e, Ts...&& args) {
auto r = events.equal_range( e );
for (auto it = r.first; it != r.second; ++it)
{
auto&& f = boost::any_cast<std::function<Signature> const&>(it.second);
f(std::forward<Ts>(args)...);
}
}
private:
static std::unordered_multimap<unsigned int, boost::any> events;
};
在这里,您可以在两端传递函数签名,如void()
或void(int)
。这些类型必须完全匹配。
我将fire_event
的自变量完美地转发到我从映射中提取的函数。
我做了一些其他的改进,比如正确地移动/放置并删除了一些伪造的副本。
由于以下几个原因,推导lambda的签名是个坏主意。首先,因为C++14 auto
Lambda即将问世。其次,这意味着lambda或函数将T const&
或T
或任何"泄漏"到您必须如何调用它的东西中(您的原始实现要求所有值都按值取值)。
给定事件的签名现在会明确列出在哪里注册和在哪里触发。如果不匹配,应该更容易注意到。
我也会尝试从指针any_cast
,并断言它是非null的,而不是在签名错误时抛出。
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 是否可以从int转换为enum类类型
- 构造函数正在调用一个使用当前类类型的函数
- 我应该使用什么来代替void作为变体中的替代类型之一
- 类中的字符串不命名类型