C ++为什么编译器无法生成返回Lambda中捕获变量的const引用的代码

时间:2019-02-08 04:03:44

标签: c++ lambda

我正在观看Jason Turner关于IIFE的谈话。有一个示例看起来像下面的代码:

#include <iostream>
#define EOL '\n'
using std::cout;

class C
{
public:
    C(){ std::cout << "Def ctor\n"; }
    C(const C &c){ std::cout << "Copy ctor\n" << EOL; }
    C(C&& c){ std::cout << "Move ctor\n" << EOL; }
    ~C(){ std::cout << "Dtor\n"; }

    void Print() const { cout << "address: " << this << EOL; }
};
int main()
{
    C c;
    c.Print();
    const auto &refc = [&](){ 
        cout << "lambda returns..." << EOL;
        return c; }();
    refc.Print();
    return 0;
}

输出为:

Def ctor
address: 0x7ffe6a6765bf
lambda returns...
Copy ctor
address: 0x7ffe6a6765be
Dtor
Dtor

这表明返回值正在使用copy构造函数,而将返回值定义为const引用,并创建一个新复制的对象以返回const引用。

但是如果lambda定义为:

const auto &refc = [&]()->const auto&{ 
    cout << "lambda returns..." << EOL;
    return c; }();

没有调用副本ctor,结果为:

Def ctor
address: 0x7fff319dc2af
lambda returns...
address: 0x7fff319dc2af
Dtor

我认为无需复制,设计背后是否有充分的理由?我想知道在什么情况下复制捕获的变量有用吗?

1 个答案:

答案 0 :(得分:1)

lambda上的文档告诉我们,如果未指定尾随返回类型,则lambda的返回类型是什么:

  

省略的尾随返回类型:闭包operator()的返回类型是从返回语句推导出的,就好像其返回类型声明为 auto

因此它导致复制构造函数被调用。

如果要防止这种情况,可以将auto&const auto&用作尾随返回类型。