C++ 可调用体作为模板类的模板构造函数的参数遇到的一些问题

2 篇文章 0 订阅
1 篇文章 0 订阅

C++ 可调用体作为模板类的模板构造函数的参数遇到的一些问题

最近在捣鼓C++的多线程编程、在C++20的标准库中新增了标准线程库thread,这个库非常好用、可以为函数指针具有括号运算符成员函数的结构体或对象、甚至lambda表达式创建运行它们的线程。

如果使用C++20之前的C++版本、是没有thread这个线程库的,如果在单片机上使用C++的话标准线程库可能也得不到很好的支持

目前armclang只支持到c++17 用它连标准线程库都没有

我自己写了一个用在C++的线程库,它提供类似std::thread的功能;它实际上是个中间件、需要系统支持(windows有CreateThread,单片机有各种RTOS)

这个中间件能像std::thread那样启动运行lambda的线程,这个特性能极大方便在C++中编写涉及多线程的内容。

问题

std::thread需要在构造函数中传入可调用对象,我的线程库也应该可以这样,但是在这出现了问题。

我的线程库

这里放出简化的代码、以便于后续的讨论:

namespace H{

  class Thread_LL_Abstract;//线程低层抽象

  //线程类
  template<class Thread_LL>
  class Thread{
    public:
      template<typename T_Invoke,typename... T_Args>
      Thread(T_Invoke&& invoke,T_Args&&... args){
        Construction(static_cast<T_Invoke&&>(invoke),static_cast<T_Args&&>(args)...);
      }
  };
	
  class Thread_LL_std:public Thread_LL_Abstract;//继承了线程低层抽象,不同的系统上有不同的实现;
  //Thread_LL_std在windows上封装了std::thread或者CreateThread 单片机上可以封装FreeRTOS的相关函数

  using Thread_std=Thread<Thread_LL_std>;//线程类模板特化,后续使用Thread_std来创建线程

}

线程类Thread是一个模板、其构造函数也是一个模板。

出现问题的代码

我先后在mingw64 (v13.2.0)与armclang6.19进行测试、结果一致。

  std::string s="123";

  //下面的代码出现了问题
  H::Thread_std thread=H::Thread_std([](std::string& s) {
    std::cout<<"Thread Run"<<s<<std::endl;
    s="456";
  },std::ref(s));

  thread.Start();
  thread.Join();
  std::cout<<s<<std::endl;

这段代码在C++17与C++20中是正常的,但在C++11与C++14则发生了错误:
报错
可以发现、编译器将模板形参T_Invoke识别为了H::Thread<H::Thread_LL_std> (即Thread_std)。但是代码里要创建的对象就是Thread_std、根本没有为模板类型列表提供Thread_std这个类型,这里正确的行为应该是T_Invoke=lambda [](std::string &s)->void(或者与lambda相关的类型、反正不应该是Thread_std)

如果不是在C++20下编译发现正常, 就真的以为是自己代码的问题了。

我后续使用一个更简单的例子尝试复现这个错误、但是失败了,这个错误的触发条件不明确。

解决方法

将出问题的代码改成:

  H::Thread_std thread([](std::string& s) {
    std::cout<<"Thread Run"<<s<<std::endl;
    s="456";
  },std::ref(s));

也就是换了一种声明/构造格式,居然能编译通过了,而且运行正常。

通过new的方式也是没问题的:

  H::Thread_std* pthread=new H::Thread_std([](std::string& s) {
    std::cout<<"Thread Run"<<s<<std::endl;
    s="456";
  },std::ref(s));

出问题的就只有H::Thread_std thread=H::Thread_std()这种构造形式的代码。

问题也算是有了一个解决方法,可以愉快的在类内创建调用成员函数的线程了

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值