c++ - smart - programar contratos inteligentes
tipo de objeto capturado de referencia dentro de lambda (1)
El siguiente código funciona con gcc
#include <map>
int main() {
std::map<int, double> dict;
const auto lambda = [&]()
{
decltype(dict)::value_type bar;
};
}
Pero para msvc tengo que usar adicionalmente 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;
};
}
De lo contrario me sale un 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
¿Qué compilador muestra el comportamiento correcto según el estándar?
actualizar:
Para msvc decltype(dict)
realmente es una referencia, como el siguiente código
#include <map>
int main()
{
std::map<int, double> dict;
const auto lambda = [&]()
{
decltype(dict) foo;
};
}
errores con
error C2530: ''foo'': references must be initialized
Si este es realmente un comportamiento incorrecto, podría dar lugar a errores desagradables, como referencias colgantes cuando el código se compila con msvc.
#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
};
}
No hay una regla especial con respecto a las aplicaciones de paréntesis no entre paréntesis (es decir, [expr.prim.lambda]/20 no se aplica [expr.prim.lambda]/20 ). Por lo tanto, simplemente recurrimos a la definición habitual de decltype
, que exige que si el operando es una expresión-id , el tipo decltype
es solo el tipo declarado de la entidad, y eso no es un tipo de referencia. Por lo tanto, VC ++ está equivocado.
NB: no importa si el dict
se captura o no, porque ¶17 :
Cada id-expresión dentro de la declaración compuesta de una lambda-expresión que es un odr-use (3.2) de una entidad capturada por copia se transforma en un acceso al miembro de datos correspondiente sin nombre del tipo de cierre. [ Nota : una expresión-id que no es un uso de odr se refiere a la entidad original , nunca a un miembro del tipo de cierre. Además, tal expresión-id no causa la captura implícita de la entidad. - nota final ]
decltype
nunca odr utiliza ninguno de sus operandos o suboperandos. Esta regla se vuelve bastante problemática a veces, por ejemplo, como se muestra en el problema central 958 :
int f (int&); void* f (const int&); int main() { int i; [=] ()-> decltype(f(i)) { return f(i); }; }
Aquí, decltype(f(i))
usa el non- const
i
del ámbito que lo incluye. Sin embargo, dado que la lambda no es mutable
, la i
en el cuerpo es en realidad const
, por lo tanto, el tipo de retorno es incorrecto. El CWG concluyó que esto surge con poca frecuencia para que valga la pena resolverlo.