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?

StackOverflow https://stackoverflow.com/questions/2335530

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?

¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top