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

如何使call_impl模板函数支持返回lambda调用的引用类型?

解决PImpl模式下call_impl返回引用的编译错误

在基于PImpl惯用法的代码实现中,尝试通过call_impl函数包装lambda并返回引用类型时,触发了编译错误。原代码如下:

#include <iostream>
#include <memory>

class FooImp
{
public:
    int& C() { return _value; }

private:
    int _value{};
};

class Foo
{
public:
    Foo() : 
        _imp{ std::make_unique<FooImp>() }
    {
    }

    int& C()
    {
        // In member function 'int& Foo::C()': cannot bind non-const lvalue reference 
        // of type 'int&' to an rvalue of type 'int'
        return call_impl([&] { return _imp->C(); });
    }

private:
    template<typename fn_t>
    auto call_impl(fn_t fn) -> decltype(fn()) 
    {
        std::cout << "Construct Measure here\n";
        
        struct OnExit{
             ~OnExit() { std::cout << "Construct Log here\n"; }
        } onExit;
        return fn();
    }

    std::unique_ptr<FooImp> _imp;
};

int main()
{
    Foo foo;
    std::cout << foo.C() << "\n";
    return 0;
}

编译错误信息

error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
24 | return call_impl([&] { return _imp->C(); });
| ~^~~~~~~~~~~~~~~~~~~

错误原因

默认情况下,lambda的返回值会被隐式退化为右值:即使_imp->C()返回的是int&类型的左值引用,lambda会返回该引用绑定值的副本(右值),而非原引用。当call_impl返回这个右值时,无法将其绑定到Foo::C()声明的int&返回类型,从而触发编译错误。

可行解决方案

方案1:显式指定lambda的返回类型为引用

修改lambda,通过-> int&显式声明返回引用类型,避免返回值被隐式退化:

int& C()
{
    return call_impl([&]() -> int& { return _imp->C(); });
}

此方案中,lambda会直接返回原引用,call_impl的返回类型也会推导为int&,与外层函数的返回要求匹配。

方案2:使用decltype(auto)优化call_impl的返回类型推导

修改call_impl的返回类型为decltype(auto),该类型会精准推导fn()的返回值类型(包括引用属性),无需修改lambda:

template<typename fn_t>
decltype(auto) call_impl(fn_t fn) 
{
    std::cout << "Construct Measure here\n";
    
    struct OnExit{
         ~OnExit() { std::cout << "Construct Log here\n"; }
    } onExit;
    return fn();
}

decltype(auto)会严格保留fn()的返回类型——如果fn()返回引用,call_impl也会返回相同的引用类型,完美适配外层函数的返回要求。

验证结果

采用任意一种方案修改后,代码均可正常编译运行,输出如下:

Construct Measure here
0
Construct Log here

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:38:39