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

为何std::async无法匹配重载成员函数而lambda可正常调用?

问题说明

注意:本问题不询问如何让下方代码片段正常运行,相关解决方案已有公开讨论。核心疑问为:为何std::async本身无法找到匹配的重载函数,但lambda表达式却可以?编译器报错提示不存在如下形式的匹配调用:

'async(std::launch, <unresolved overloaded function type>, std::shared_ptr<Demo>, int)'

传入lambda(即[ptr=shared_from_this()](){return ptr->foo(2);)时,编译器可正确找到合适的重载版本,该差异的原因是什么?

复现代码

#include <future>
#include <functional>
#include <memory>

class Demo:public std::enable_shared_from_this<Demo> 
{
public:
    int foo(){return 0;};
    int foo(int a){return 0;};

    std::future<int> AsyncFoo1()
    {
        return std::async(std::launch::async, &Demo::foo, shared_from_this(), 2); // 该写法编译失败
        // 已知可行修复写法:
        //return std::async(std::launch::async, static_cast<int(Demo::*)(int)>(&Demo::foo), shared_from_this(), 2); 
    }

    std::future<int> AsyncFoo2()
    {
        return std::async(std::launch::async, [ptr=shared_from_this()](){return ptr->foo(2);});
    }
};

int main()
{

}

编译器报错信息

<source>: In member function 'std::future<int> Demo::AsyncFoo1()':
<source>:13:26: error: no matching function for call to 'async(std::launch, <unresolved overloaded function type>, std::shared_ptr<Demo>, int)'
   13 |         return std::async(std::launch::async, &Demo::foo, shared_from_this(), 2);
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future:1769:5: note: candidate: 'template<class _Fn, class ... _Args> std::future<typename std::__invoke_result<typename std::decay<_Tp>::type, typename std::decay<_Args>::type ...>::type> std::async(launch, _Fn&&, _Args&& ...)'
 1769 |     async(launch __policy, _Fn&& __fn, _Args&&... __args)
      |     ^~~~~
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future:1769:5: note:   template argument deduction/substitution failed:
<source>:13:26: note:   couldn't deduce template parameter '_Fn'
   13 |         return std::async(std::launch::async, &Demo::foo, shared_from_this(), 2);
      |                ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future:1803:5: note: candidate: 'template<class _Fn, class ... _Args> std::future<typename std::__invoke_result<typename std::decay<_Tp>::type, typename std::decay<_Args>::type ...>::type> std::async(_Fn&&, _Args&& ...)'
 1803 |     async(_Fn&& __fn, _Args&&... __args)
      |     ^~~~~
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future:1803:5: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future: In substitution of 'template<class _Fn, class ... _Args> std::future<typename std::__invoke_result<typename std::decay<_Tp>::type, typename std::decay<_Args>::type ...>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {}]':
<source>:13:26:   required from here
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/future:1803:5: error: no type named 'type' in 'struct std::__invoke_result<std::launch>'
原因解答
  • 直接传入&Demo::foo编译失败的核心是重载歧义引发模板参数推导失败:
    Demo中定义了两个签名不同的同名foo成员函数,单独取&Demo::foo时,编译器看到的是一组重载函数集合,没有唯一确定的类型。而std::async是函数模板,推导可调用对象对应的模板参数_Fn时,只会检查传入实参本身的类型,不会结合后续传入的shared_from_this()、整数2等参数反推需要的成员函数签名,因此无法确定_Fn的具体类型,推导直接失败。
  • 传入lambda可以正常编译,是因为lambda不存在类型歧义,且重载解析的时机完全不同:
    lambda本质是编译器生成的匿名类实例,从定义完成就有唯一确定的类型,不存在重载歧义,std::async可以顺利完成模板参数推导。而ptr->foo(2)的调用写在lambda函数体内部,重载解析发生在lambda自身的编译阶段,此时编译器可以明确看到调用时传入了int类型的参数2,自然能精准匹配到int foo(int a)这个重载版本,不会把重载歧义带到std::async的模板推导环节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:48:29