You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++使用std::thread调用类成员函数Compress报C2893、C2672错误

问题背景

我在实现Threads类,用于调度20个执行具体任务的Thread类实例。Thread类包含核心方法Compress以及线程状态属性(如是否繁忙标识),Threads类将所有Thread实例存储在名为threads的std::vector容器中。
程序单线程调用逻辑可正常运行,但在Threads实现文件中使用std::thread调用Thread类的Compress方法时,编译阶段出现报错。核心相关代码如下:

Thread.h

class Thread
{
public:
    BOOL isBusy = FALSE;
    Threads *threadParent;
    Thread();
    ~Thread();
    BOOL Compress() { return prvCompress(); }
private:
    BOOL prvCompress();
};

Threads.h

class Threads
{
public:
    std::vector<Thread> threads;
    File *myFile;
    Threads(File *myFile_);
    ~Threads();
    BOOL CallCompress() { return prvCallCompress(); }
private:
    BOOL prvCallCompress();
};

Threads.cpp

BOOL Threads::prvCallCompress()
{
    //for (UIN8 i = 0; i < ThreadsNumber; i++)
    //  std::thread(threads[i].Compress()).detach();

    std::thread(this->threads.at(0).Compress()).detach();
    return FALSE;
}

编译错误信息

Error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&) noexcept(<expr>)'
报错位置:...\VisualStudio\VC\Tools\MSVC\14.32.31326\include\thread 第51行

Error C2672: 'invoke': no matching overloaded function found
报错位置:...\VisualStudio\VC\Tools\MSVC\14.32.31326\include\thread 第55行

已完成排查

  • 不使用std::thread直接调用Compress方法,可正常运行无报错
  • 改用lambda作为std::thread入口,在线程内访问threads[0]的成员变量可正常执行,返回结果符合预期,对应代码如下:
std::thread([&] { std::cout << threads[0].wasntUsed << std::endl; }).detach();
  • 仅创建std::thread实例传入Compress调用、不执行detach操作,依然触发相同编译错误,对应代码如下:
std::thread(this->threads.at(0).Compress());

错误原因

你写的std::thread(this->threads.at(0).Compress())存在语法逻辑错误:这行代码会先在当前线程直接执行Compress()方法,拿到它的BOOL类型返回值,再把这个整数值传给std::thread的构造函数。
std::thread构造函数要求第一个入参必须是可调用对象(函数指针、lambda、重载了()运算符的对象等),BOOL类型显然不满足可调用要求,因此编译器会报std::invoke找不到匹配重载的错误。
你直接调用Compress能跑通、lambda里访问成员能跑通,都是因为这两种场景没有把Compress的返回值当成可调用对象传给thread构造,逻辑是对的。

解决方案

有两种正确的写法可以实现新线程调用Compress方法:

  1. 传成员函数指针+对应实例地址
    非静态成员函数的调用必须绑定具体的对象实例,给std::thread传参时需要先传成员函数指针,再传对应的对象指针:
    // 单个线程启动写法
    std::thread(&Thread::Compress, &this->threads.at(0)).detach();
    
    // 批量启动循环写法示例
    for (size_t i = 0; i < threads.size(); i++)
    {
        std::thread(&Thread::Compress, &threads[i]).detach();
    }
    
  2. 用lambda包裹调用逻辑(推荐,可读性更强,不易写错)
    就是你之前验证过可行的lambda写法,把Compress调用放到lambda函数体内即可:
    // 单个线程启动写法
    std::thread([this]() {
        threads.at(0).Compress();
    }).detach();
    
    // 批量启动循环写法示例,注意按值捕获索引避免悬空引用
    for (size_t i = 0; i < threads.size(); i++)
    {
        std::thread([this, i]() {
            threads[i].Compress();
        }).detach();
    }
    

额外注意事项

你当前使用detach()分离线程,需要保证线程执行的整个周期内,threads容器内的Thread对象不会被销毁,也不要触发vector扩容(扩容会导致原有对象内存地址变化),否则会触发野指针访问的未定义行为。如果对生命周期管控没有把握,建议用join()等待线程执行完成再退出作用域。


内容的提问来源于stack exchange,提问作者user15044282

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:18:03