lambda中引用捕获对象的类型

时间:2016-10-19 12:12:45

标签: c++ lambda language-lawyer decltype

以下代码适用于gcc

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.enableComplexMapKeySerialization();
Gson mapper = gsonBuilder.create();
//Object to JSON in String
String jsonInString = mapper.toJson(myobject); //myobject=any object of class A

但对于msvc,我还必须使用#include <map> int main() { std::map<int, double> dict; const auto lambda = [&]() { decltype(dict)::value_type bar; }; }

std::remove_reference

否则我得到an error

#include <map>
#include <type_traits>

int main() {
    std::map<int, double> dict;
    const auto lambda = [&]()
    {
        std::remove_reference_t<decltype(dict)>::value_type bar;
    };
}

哪个编译器根据标准显示正确的行为?

更新

对于msvc error C2651: 'std::map<int,double,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>> &': left of '::' must be a class, struct or union ,确实是一个参考,如下面的代码

decltype(dict)

错误

#include <map>

int main()
{
    std::map<int, double> dict;
    const auto lambda = [&]()
    {
        decltype(dict) foo;
    };
}

如果这确实是错误的行为,那么在使用msvc编译代码时可能会导致nasty bugs, like dangling references

error C2530: 'foo': references must be initialized

1 个答案:

答案 0 :(得分:12)

没有关于decltype的非括号内应用的特殊规则(即[expr.prim.lambda]/20不适用)。所以我们回到decltype的通常定义,它要求如果操作数是 id-expression ,则yielding类型只是实体的声明类型,而且&# 39;不是参考类型。因此VC ++是错误的。

注意:是否捕获dict并不重要,因为¶17

  

lambda-expression 复合语句中的每个 id-expression ,这是一个odr-use(3.2) 将由副本捕获的实体转换为对相应的未命名数据成员的访问权限   闭合类型。 [注意 id-expression 不是odr-use指的是原始实体,永远不会成为   封闭类型。此外,这样的 id-expression 不会导致实体的隐式捕获。 - 结束   注意]

decltype永远不会使用任何操作数或子操作。这条规则实际上有时会出现问题,例如:如core issue 958所示:

int f (int&);
void* f (const int&);

int main()
{
   int i;
   [=] ()-> decltype(f(i)) { return f(i); };
}

此处,decltype(f(i))使用封闭范围内的非const i。但是,由于lambda不是mutable,因此正文中的i实际上是const,因此尾随返回类型不正确。 CWG认为这种情况很少发生,值得解决。