微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C ++ 17模板参数推导失败

如何解决C ++ 17模板参数推导失败

我想模拟一个计时器,该计时器会定期为我在以下代码段(天真)中编写的函数调用(回调),其中, 主函数中的Timer / / ..行的参数推导失败。我正在用c ++ 17 std编译此代码。我该如何解决?还是那些必要的论点? 在这方面的任何帮助都将受到赞赏。

#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 ,无论它们是什么。然后继续进行,您的函数只需要转换为std :: function。

现在,它将您的使用与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 举报,一经查实,本站将立刻删除。