C++11 无法按值捕获随机引擎

C++11 无法按值捕获随机引擎,c++11,lambda,C++11,Lambda,我有GCC8无法编译的代码,但我不明白为什么 #include <iostream> #include <algorithm> #include <random> using namespace std; template<class... T> void diagnose(T... x); int main() { auto d = normal_distribution<double>(0.0, 1.0); au

我有GCC8无法编译的代码,但我不明白为什么

#include <iostream>
#include <algorithm>
#include <random>
using namespace std;

template<class... T>
void diagnose(T... x);

int main()
{
    auto d = normal_distribution<double>(0.0, 1.0);
    auto g = default_random_engine();
    cout << d(g) << endl;
    auto gen = [=](){
        //diagnose(d, g);
        return d(g);   // ******
    };
    cout << gen() << endl;
}
但是,如果我将捕获更改为通过引用,则代码可以工作

如果我取消注释注释注释的
//diagnose
行,错误消息如下(还需要将
返回d(g)
更改为
返回1.0
):

对“无效诊断(标准::正态分布,标准::线性一致引擎)”的未定义引用
如您所见,在按值捕获的情况下,参数
g
是常量引用。但是
常量
不会出现在诊断中


有人能解释一下这里发生了什么吗?

您正在通过值
[=]
传递
d
,所以这个对象的副本是在lambda内部创建的,但是lambda函数的主体是
const
,所以您不能更改lambda主体内部的对象<代码>正态分布::运算符()成员不是常量。在常量成员中,只能为成员对象调用常量方法。您可以通过向lambda添加mutable来解决此问题

 auto gen = [=]() mutable {
    //diagnose(d, g);
    return d(g);   // ******
};
或通过引用传递
d

 auto gen = [&](){
        //diagnose(d, g);
        return d(g);   // ******
    };

答案很好(+1),但我认为“lambda函数体是常量”应该更好地表示为“复制捕获的对象是lambda体中的常量”,我的意思是lamba的体被翻译成
unnamedClass::operator()const{}
所以它是const member方法。我意识到
diagose
函数无法检测cv限定符。为了正确报告cv限定符,我们可能需要使用通用参考
T&&…
 auto gen = [=]() mutable {
    //diagnose(d, g);
    return d(g);   // ******
};
 auto gen = [&](){
        //diagnose(d, g);
        return d(g);   // ******
    };