为什么lambda的call-operator隐式为const?

时间:2018-11-23 11:27:51

标签: c++ c++11 lambda const function-call-operator

我在以下函数中有一个小的“ lambda表达式”:

int main()
{
    int x = 10;
    auto lambda = [=] () { return x + 3; };
}

下面是为上述lambda表达式生成的“匿名闭包类”。

int main()
{
    int x = 10;

    class __lambda_3_19
    {
        public: inline /*constexpr */ int operator()() const
        {
            return x + 3;
        }

        private:
            int x;

        public: __lambda_3_19(int _x) : x{_x}
          {}

    };

    __lambda_3_19 lambda = __lambda_3_19{x};
}

由编译器生成的闭包的“ operator()”是隐式常量。为什么标准委员会默认将其设置为const

3 个答案:

答案 0 :(得分:18)

在open-std.org上由Herb Sutter找到了paper,讨论了此事。

  

奇怪的一对:按值注入的常量和古怪的可变性来捕获
  考虑以下示例,程序员通过值捕获局部变量并尝试修改捕获的值(它是lambda对象的成员变量):

int val = 0;
auto x = [=]( item e ) // look ma, [=] means explicit copy
 { use( e, ++val ); }; // error: count is const, need ‘mutable’
auto y = [val]( item e ) // darnit, I really can’t get more explicit
 { use( e, ++val ); }; // same error: count is const, need ‘mutable’
     

添加此功能的原因是担心用户可能不会意识到自己获得了副本,尤其是由于Lambda是可复制的,因此他可能会更改其他Lambda的副本。 < / p>

以上引用和示例说明了为什么标准委员会可能默认将其设置为const,并要求mutable对其进行更改。

答案 1 :(得分:9)

来自cppreference

  

除非在lambda表达式中使用了关键字mutable,否则函数调用运算符是const限定的,并且从复制operator()内部获取的被复制捕获的对象是不可修改的

对于您来说,复制捕获的内容是不可修改的。

我想,如果你写的东西是

int x = 10;

auto lambda = [=] () mutable { x += 3; return x; };

const应该消失

-编辑-

OP精确

  

我已经知道添加可变变量可以解决此问题。问题是我想了解默认情况下使lambda不可变的原因。

我不是语言律师,但我看来这很明显:如果您使operator()而不是const,您将无法像

template <typename F>
void foo (F const & f)
 { f(); }

// ...

foo([]{ std::cout << "lambda!" << std::endl; });

我的意思是...如果operator()不是const,则不能使用将它们作为const引用传递的lambda。

当不是严格需要时,应该是一个不能接受的限制。

答案 2 :(得分:0)

我认为,当lambda中的变量不引用最初捕获的内容时,只是为了避免混淆。在词法上,这样的变量就好像在其“原始”范围内一样。复制主要是为了延长对象的寿命。当捕获不是复制时,它指的是原始文件,并且对原始文件进行了修改,并且由于两个不同的对象(其中一个对象是隐式引入的)而不会引起混淆,并且lambda的const函数调用运算符允许这样做。 / p>