以下代码适用于gcc
#include <map>
int main() {
std::map<int, double> dict;
const auto lambda = [&]()
{
decltype(dict)::value_type bar;
};
}
但是对于msvc,我必须另外使用std::remove_reference
#include <map>
#include <type_traits>
int main() {
std::map<int, double> dict;
const auto lambda = [&]()
{
std::remove_reference_t<decltype(dict)>::value_type bar;
};
}
否则我会得到an error
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
根据标准,哪个编译器显示了正确的行为?
更新:
对于msvc来说,decltype(dict)
确实是一个参考,如以下代码所示
#include <map>
int main()
{
std::map<int, double> dict;
const auto lambda = [&]()
{
decltype(dict) foo;
};
}
错误:
error C2530: 'foo': references must be initialized
如果这确实是错误的行为,当使用msvc编译代码时,可能会导致nasty bugs, like dangling references。
#include <map>
std::map<int, double> return_a_map()
{
std::map<int, double> result;
return result;
}
int main()
{
std::map<int, double> dict;
const auto lambda = [&]()
{
decltype(dict) foo = return_a_map();
// foo is a dangling reference in msvc
};
}
发布于 2016-10-19 20:51:53
关于decltype
的非括号应用程序没有特殊规则(即,[expr.prim.lambda]/20不适用)。所以我们只需要回到通常的decltype
定义,它要求如果操作数是一个id表达式,那么产生的类型就是实体的声明类型,而不是引用类型。因此,VC++是错误的。
注意:dict
是否被捕获并不重要,因为¶17
作为由copy捕获的实体的odr使用(3.2)的复合语句内的每个id表达式都被转换为对闭包类型的相应的未命名数据成员的访问。注意:对于不是odr-的 id-expression ,它指的是原始实体类型,而不是闭包类型的成员。此外,这样的id表达式不会导致对实体的隐式捕获。-结束注释
decltype
从不odr-使用它的任何操作数或子操作数。实际上,这个规则有时会出现很多问题,如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得出的结论是,这种情况出现的频率太低,不值得解决。
https://stackoverflow.com/questions/40131096
复制相似问题