Depois de examinar a resolução proposta no # 1664 ( resolução proposta no 1664 ), estou confuso com as regras de um argumento padrão de um modelo de função, cite o conteúdo aqui:
De acordo com 8.1.5 [expr.prim.lambda] parágrafo 3
O tipo de fechamento é declarado no menor escopo de bloco, escopo de classe ou espaço de nome que contém a expressão lambda correspondente. [Nota: isso determina o conjunto de espaços para nome e classes associados ao tipo de fechamento (6.4.2 [basic.lookup.argdep]). Os tipos de parâmetro de um declarador lambda não afetam esses espaços de nomes e classes associados. - end note]
No entanto, o parágrafo 13.8.1 [temp.inst] 13 diz
Se um modelo de função f for chamado de uma maneira que exija a utilização de um argumento padrão, os nomes dependentes serão consultados, as restrições semânticas serão verificadas e a instanciação de qualquer modelo usado no argumento padrão será feita como se o argumento padrão havia sido um inicializador usado em uma especialização de modelo de função com o mesmo escopo, os mesmos parâmetros de modelo e o mesmo acesso que o modelo de função f usado naquele momento.
Uma possibilidade, então, é que o tipo de fechamento da expressão lambda em um argumento padrão para uma função de modelo (ou, presumivelmente, uma função de membro de um modelo de classe) seja considerado como declarado em algum escopo de bloco no corpo de a especialização do modelo de função fictícia.
Considere o seguinte exemplo:
namespace J {
inline namespace K {
template <typename T> int zap(const T &t) { foo(t); return 0; }
template <typename T> void zip(int = zap([] { })) { }
}
template <typename T> void foo(const T &) { }
}
void bar() {
J::K::zip<long>();
/*Accroding to the above wording,the invoke just like:
=> J::K::zip<long>(zap([] { }));
*/
}
Se o zip não era um modelo, a pesquisa dependente de argumento resolve com êxito a pesquisa de foo em todas as implementações testadas; no entanto, há variação de implementação no tratamento do exemplo, conforme escrito.
Proposta de resolução (setembro de 2013):
Altere 17.8.1 [temp.inst] parágrafo 13 da seguinte maneira:
Se um modelo de função f for chamado de uma maneira que exija a utilização de um argumento padrão, os nomes dependentes serão consultados, as restrições semânticas serão verificadas e a instanciação de qualquer modelo usado no argumento padrão é feito como se o argumento padrão tivesse sido um inicializador usado em uma especialização de modelo de função com o mesmo escopo, os mesmos parâmetros de modelo e o mesmo acesso que o modelo de função f usado nesse ponto, exceto que o escopo no qual um tipo de fechamento é declarado (8.1.5 [expr.prim.lambda]) - e, portanto, seus namespaces associados - permanece como determinado no contexto da definição para o argumento padrão. Essa análise é chamada instanciação de argumento padrão. O argumento padrão instanciado é então usado como o argumento de f.
Observe a parte enfatizada, se eu não me interpretem mal, isso significa que se a peça comentário enfatizou fora, a foo
não poderia ser consultados pelo argumento olhar dependente até porque o argumento [] { }
que namespace é nem J
nem K
, assumir a forma dentro function bar
como J::K::zip<long>(zap([] { }) /*default argument*/);
, Então accroding para [ expr.prim.lambda] parágrafo 3 o namespace de [] { }
está em fuction bar
e nesse escopo, não há nenhum foo
, portanto a parte enfatizada é para esse caso que considera o namespace de [] { }
dentro zap
como o mesmo que zap
, significa que o namespace de [] { }
é K
, Agora o foo
pode ser encontrado no espaço para nome paiJ
por regras de pesquisa dependentes de argumento, Até agora, se eu interpretar mal essas regras, corrija-me. a outra visão de ponto é que o argumento padrão é avaliado sempre que a função é chamada, mesmo que o padrão seja não dependente . código a seguir:
#include <iostream>
struct A {
};
template<typename T>
int func(T, float) { //#a
std::cout << "float" << std::endl;
return 0;
}
template<typename T>
void test(int = func(A{}, 0)) { //#1
}
template<typename T>
int func(T, int) { //#b
std::cout << "int" << std::endl;
return 0;
}
int main() {
test<A>(); //#2 transform to: test<A>(func(A{}, 0)); here,#b should be the best match
std::getchar();
}
Embora o argumento padrão func
não seja dependente, ele deve ser determinado sempre que a função test
for chamada e eu testo o código em alguns complementadores.
Toda a versão do relatório MSVC "int", relatório gcc "float", relatório clang "float", que diabos? De acordo com o relatório gcc ou clang, parece que isso func
é determinado em #1
e MSVC provou que isso func
é determinado em #2
. se o MSVC estiver errado, isso significa que o argumento padrão não dependente pode ser determinado no número 1 e não é necessário determinar sempre que a função é chamada, por que a parte enfatizada precisa ser adicionada? (Se eu entendi a parte enfatizada corretamente, o objetivo é manter o namespace do tipo de fechamento dentro do argumento padrão consistente se a expressão lambda estiver no ponto da declaração da função ou no ponto de chamada ). Se eu não entendo essas regras, como interpretá-las corretamente?
ATUALIZAR:
a versão 9.1 ou superior do gcc não pode cumprir o código mencionado no # 1664, ele reportará um erro ( o resultado da conformidade )
Questões:
1.O argumento padrão não dependente do modelo de função ou da função não-modelo precisa ser determinado sempre que a função correspondente é chamada?
2. o que significa "a definição para o argumento padrão"? Esta redação é estritamente? ( Em outras palavras, meu entendimento é: que regras adicionais as regras adicionadas desejam expressar é que o espaço para nome do tipo de fechamento é o de uma declaração de função em que contém um argumento padrão que contém a expressão lambda correspondente, certo? se meu entendimento sobre isso estiver errado, corrija-me )
f
usado" na verdade parece que a especialização hipotética estaria no espaço de nomesJ::K
, não na definição debar
, mas não vejo como a frase alterada faria alguma diferença.