No es posible crear instancias de plantillas de función, que decltype usos para deducir el tipo de retorno, si se llama desde el interior de un lambda?
-
22-09-2019 - |
Pregunta
Estoy tratando de utilizar C ++ 0x, y en la expresión lambda particular y decltype para simplificar algunos de mi código, usando el compilador MSVC10 RC.
Me he encontrado el siguiente problema muy extraño:
template <typename F>
auto foo(F f) -> decltype(f()){
return f();
}
template <typename F>
void bar(F f){
f();
}
int main() {
bar([](){
foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
});
}
Como se indica en el comentario, el compilador genera un error en la línea de foo([]() { })
.
odio a gritar "error del compilador", pero realmente no se puede ver ninguna explicación bueno para este error.
Aparentemente, mientras que dentro de la expresión lambda exterior, el compilador no puede especializarse la plantilla de función foo
para el lambda interior.
Sin embargo, si la definición de foo
se cambia para codificar el tipo de retorno, así:
template <typename F>
void foo(F f){
return f();
}
A continuación, todo se compila bien.
¿Hay algún capricho oscura de decltype cuando se utiliza para deducir el tipo de retorno de los parámetros de expresión lambda dentro del alcance de otra lambda que no soy consciente de?
Solución
Estos son sólo algunos casos de prueba para que la gente observe.
Obras
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
void dummy() {}
int main()
{
auto x = []()
{ // non-lambda parameter
foo(dummy);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto f = [](){};
auto x = [&]()
{ // pre-defined lambda
foo(f);
};
}
falla
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda
foo([]{});
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda
auto f = []{};
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda, explicit return
// (explicit return type fails too, `-> void`)
auto f = [](){ return; };
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda, explicit return non-void
// (explicit return type fails too, `-> int`)
foo([]{ return 5; });
};
}
Por lo tanto, parece tener que ver con el alcance y el tipo (?) void
de la lambda interna, incluso cuando se hace explícita.
Otros consejos
La naturaleza de 'auto' es permitir compilador para calcular el tipo. Sin embargo, su primer ejemplo se contiene referencias recursivas el uno del otro, por lo que para calcular automática de foo de lo que necesita la barra y para crear una instancia de la barra que necesita el foo.
En segundo ejemplo otro lado dice explícitamente compilador: "Debería ser un puntero a la función, por lo que se calme durante un tiempo". Desde puntero a función está bien calculada tipo compilador sabe lo que va a ser reservados con exactitud. Sólo por analógico: declaración adelantada comparar miembro
struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes