如何解决C ++ 17模板参数推导失败
我想模拟一个计时器,该计时器会定期为我在以下代码段(天真)中编写的函数调用(回调),其中,
主函数中的Timer /
#include <functional>
#include <chrono>
using namespace std::chrono_literals;
template<typename ...Args>
class Timer
{
public:
Timer(std::function<void(Args...)> func,Args&&... args,std::chrono::milliseconds step)
: m_callback{ func },m_args{ std::forward<Args>(args)... },m_time{ step },m_stop{ false },{ }
private:
std::function<void(Args...)> m_callback;
std::thread m_executer;
std::tuple<Args...> m_args;
std::chrono::milliseconds m_time;
bool m_stop;
};
int main()
{
// Create a timer
auto timer = Timer/*<int,int,float>*/([](int a,int b,float c) { },15,17,12.0f,500ms);
return 0;
}
解决方法
我剔除了与您的问题无关的所有内容(您应该这样做以便更轻松地获得帮助),这就是我要做的工作。首先,我在可变参数之前移了毫秒。它会混淆编译器参数包的结尾位置,因此您通常希望...成为参数列表中的最后一件事。
第二,由于需要在将Lambda转换为std :: function之前将其转换为类,因此CTAD(类模板arg推论)不适用于您。
如果main()按预期将实际的std :: function传递到构造函数中,那么它将起作用:
auto timer = Timer(
std::function<void(int,int,float)>([](int a,int b,float c) { }),500ms,15,17,12.0f);
但这看起来比您最初尝试的要差。
更好的解决方案(有点模糊)是帮助CTAD使用c ++ 17 推导指南来弄清楚您在做什么。这是一种模式匹配,说:“如果他们尝试使用 this 语法创建此类,则实际上意味着它是 this 类型。”
这是我发现为您工作的指南:
template <typename T,typename... Args>
Timer(T&&,std::chrono::milliseconds,Args...) -> Timer<Args...>;
该指南的作用是说:他们可以将任何T &&作为第一个参数传递,并且将其忽略,即以毫秒为单位,然后是Args包中的其他类型。鉴于此,Timer的主要类型(箭头的右侧)就是Timer
现在,它将您的使用与lambda匹配,使用给定的Args实例化Timer,从中知道它可以将lambda转换为std :: function。
这是一个可行的示例,减去所有不相关的内容:
#include <functional>
#include <chrono>
using namespace std::chrono_literals;
template<typename ...Args>
struct Timer {
Timer(std::function<void(Args...)> func,std::chrono::milliseconds step,Args&&... args )
{ }
};
template <typename T,typename... Args>
Timer(T&&,Args...) -> Timer<Args...>;
int main() {
auto timer = Timer([](int a,float c) { },12.0f);
}
编译器资源管理器:https://godbolt.org/z/Wa3oK3
,这里有2个关于模板参数推导的问题。 std::function
参数不能从lambda参数推导出,推论仅适用于尾随的参数包。
要解决此问题,可以更改构造函数的参数顺序,如下所示:
Timer(std::function<void(Args...)> func,Args&&... args)
// ... // ^^^^^^^^^ trailing
并添加演绎指南
template<typename Func,typename ...Args>
Timer(Func,Args&&...) -> Timer<Args...>;
这里是demo。
请注意警告,您的成员初始化器列表与成员声明的顺序不同。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。