auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
clang ++ 3.6.0 e uma impressão mais recente "Você está usando o clang ++!" e avise que a captura
foo
não está sendo usada.g ++ 4.9.0 e mais recente, imprima "Você está usando g ++!" e avise que o parâmetro
foo
não está sendo usado.
Qual compilador está seguindo com mais precisão o padrão C ++ aqui?
struct Lambda { template<typename T> void operator()(T foo) const { /* ... */ } private: decltype(outer_foo) foo{outer_foo}; }
.Respostas:
Atualização: conforme prometido pela cadeira Core na citação inferior, o código agora está mal formado :
Houve alguns problemas relacionados à pesquisa de nomes em lambdas há um tempo atrás. Eles foram resolvidos pelo N2927 :
A pesquisa é sempre feita no contexto da expressão lambda , nunca "depois" da transformação no corpo da função de membro de um tipo de fechamento. Veja [expr.prim.lambda] / 8 :
(O exemplo também deixa claro que a pesquisa não considera de alguma forma o membro de captura gerado do tipo de fechamento.)
O nome
foo
não é (re) declarado na captura; é declarado no bloco que encerra a expressão lambda. O parâmetrofoo
é declarado em um bloco aninhado nesse bloco externo (consulte [basic.scope.block] / 2 , que também menciona explicitamente parâmetros lambda). A ordem da pesquisa é claramente do interior para o exterior . Portanto, o parâmetro deve ser selecionado, ou seja, Clang está certo.Se você fizesse da captura uma captura init, ou seja, em
foo = ""
vez defoo
, a resposta não seria clara. Isso ocorre porque a captura agora na verdade induz uma declaração cujo "bloco" não é fornecido. Enviei uma mensagem para a cadeira principal, que respondeufonte
Estou tentando juntar alguns comentários à pergunta para dar uma resposta significativa.
Antes de tudo, observe que:
foo
Portanto, a lógica me faria dizer, à primeira vista, que o parâmetro deve sombrear a variável capturada como se estivesse em:
De qualquer forma, o @nm observou corretamente que os membros de dados não estáticos declarados para variáveis capturadas por cópia são na verdade sem nome. Dito isto, o membro de dados sem nome ainda é acessado por meio de um identificador (ou seja
foo
). Portanto, o nome do parâmetro do operador de chamada de função ainda deve (digamos) sombrear esse identificador .Como corretamente apontado por @nm nos comentários à pergunta:
Por causa disso, eu diria que o clang está certo.
fonte