C++ 为什么lambda';s调用运算符隐式常量?

C++ 为什么lambda';s调用运算符隐式常量?,c++,c++11,lambda,constants,function-call-operator,C++,C++11,Lambda,Constants,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

我在下面的函数中有一个小的“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

除非lambda表达式中使用了关键字
mutable
,否则函数调用操作符是const限定的,并且通过copy捕获的对象在此
操作符()中是不可修改的

在您的情况下,复制捕获的任何内容都是不可修改的

我想,如果你写一些

int x = 10;

auto lambda = [=] () mutable { x += 3; return x; };
template <typename F>
void foo (F const & f)
 { f(); }

// ...

foo([]{ std::cout << "lambda!" << std::endl; });
const
应该消失

--编辑--

OP精确

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

我不是语言律师,但这一点似乎很明显:如果你让
operator()
不是
const
,你就不能让某个东西像

int x = 10;

auto lambda = [=] () mutable { x += 3; return x; };
template <typename F>
void foo (F const & f)
 { f(); }

// ...

foo([]{ std::cout << "lambda!" << std::endl; });
模板
无效foo(F const&F)
{f();}
// ...
foo([]{std::cout在open-std.org上的Herb Sutter发现了这一点,该网站讨论了这一问题

奇数对:通过值的注入常数和奇怪的可变项捕获
考虑这个Struman例子,程序员通过值捕获一个局部变量,并尝试修改捕获的值(它是lambda对象的成员变量):

添加此功能似乎是出于担心用户可能没有意识到自己获得了副本,特别是因为lambda是可复制的,所以他可能会更改另一个lambda的副本。


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

我认为,当lambda中的变量不是指最初捕获的内容时,这只是为了避免混淆。从词汇上讲,这样的变量就好像在其“原始”的范围内.复制主要是为了延长对象的生存期。当捕获不是通过复制时,它指的是原始的,修改应用于原始的,并且不会因为两个不同的对象(其中一个是隐式引入的)而产生混淆,它是lambda的const函数调用运算符所允许的。

@Bathsheba据我所知,它是由编译器生成的,因此没有一个学派认为所有变量默认都应该是const。也许这种想法有一些影响?@gurram我想问题应该是为什么不呢?为什么我会这样做t非常量,因此无理由限制lambda?@gurram考虑按值捕获指针,这会复制指针而不是它指向的对象。如果您能够调用对象的非常量函数,则可能会修改对象,可能会以不需要的方式或导致UB。如果
运算符()
函数被标记为
const
,这是不可能的。我们必须将成员函数显式声明为
const
,而非const是默认值。奇怪的是,当
auto
返回类型可能是自然的时,我们会重复函数的返回类型。从某种意义上讲LAMBDAS让你看到C++是如何从头开始重新创建的。通过常数引用传递函数对象是奇怪的。标准库(几乎?)总是按值传递可调用项,希望调用方根据需要使用
std::reference\u wrapper
。@Deduplicator-我想这取决于具体情况。一般来说,我不认为有什么好的理由在被调用的方法不更改对象本身时强制可调用项是可修改的。@Deduplicator虽然按值传递或转发引用更常见,传递const ref并不奇怪。我认为这个答案是
std::function
const
限定符的原因。但是对于lambda来说,这并不令人信服,因为lambda在默认情况下肯定是可变的,并且需要一个
const
限定符来表示常量。
[]()const{…}
在我看来更为一致。“lambda是可复制的”参数似乎很强。这意味着将lambda传递给
std::sort
,然后尝试在
std::sort
之外再次使用它(或者在第二次调用
std::sort
)不会显示由
std::sort
中的调用所做的任何更改,对吗?@ShadowRanger:这就是我的理解。不过我没有测试它。你应该可以。只需单击即可。结果是“找不到页面”。