Incapaz de instanciar modelos de função que usam o dttype para deduzir o tipo de retorno, se chamado de dentro de um lambda?

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

Pergunta

Estou tentando usar o C ++ 0x e, em particular, a expressão Lambda e o DONTTYPE para simplificar parte do meu código, usando o compilador MSVC10 RC.

Eu encontrei o seguinte problema muito estranho:

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)'
  });
}

Conforme indicado no comentário, o compilador gera um erro na linha foo([]() { }).

Eu odeio gritar "Bug do compilador", mas realmente não consigo ver nenhuma boa explicação para esse erro. Aparentemente, enquanto dentro da expressão externa de lambda, o compilador não pode especializar o foo Modelo de função para o lambda interno.

No entanto, se a definição de foo é alterado para o código hardcode o tipo de retorno, como este:

template <typename F>
void foo(F f){
  return f();
}

Então tudo compila muito bem.

Existe alguma peculiaridade obscura de Dettype quando usada para deduzir o tipo de retorno de parâmetros de expressão lambda dentro do escopo de outro lambda que eu não estou ciente?

Foi útil?

Solução

Estes são apenas alguns casos de teste para as pessoas observarem.

Funciona

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);
            };
}

Falha

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; }); 
            };
}

Então parece ter a ver com escopo e a void Tipo do lambda interno, mesmo quando explícito.(?)

Outras dicas

A natureza do 'AUTO' é permitir que o compilador calcule o tipo. Mas seu primeiro exemplo é contém referências recursivas umas sobre as outras; portanto, para calcular os automóveis de Foo, você precisa da barra e para criar uma instância de barra que precisa do Foo.

Por outro lado, o segundo exemplo diz explicitamente ao Compiler: "Deve ser um ponteiro funcionar, então acalme -se por um tempo". Como o ponteiro para a função é bem calculado o compilador de tipos sabe o que exatamente será reservado. Apenas para analógico: Compare a declaração avançada do membro

struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top