Como o C++20 nos deu lambdas em contexto não avaliado, posso escrever o seguinte código.
template <class = decltype([]{})>
class MyType {};
Se eu incluísse essa definição em várias TUs, isso seria uma violação do ODR?
Estou analisando em particular o §6.3(13.13) do N4860:
Em cada uma dessas definições, [...] um argumento de modelo padrão usado por um template-id (implícito ou explícito) ou simple-template-id é tratado como se sua sequência de tokens estivesse presente na definição de D; ou seja, o argumento padrão ou argumento de modelo padrão está sujeito aos requisitos descritos neste parágrafo (recursivamente).
que eu li como, decltype([]{})
é parte do tipo declarado, que é então um exemplo explicitamente rotulado como inválido pelo artigo original (§4). Estou lendo isso corretamente?
Edição 1: aqui está outra citação do mesmo parágrafo do padrão que considero muito confusa:
Pode haver mais de uma definição de uma
[...]
(13.4) — entidade modelo (13.1),
[...]
(13.6) — argumento modelo padrão
em um programa, desde que cada definição apareça em uma unidade de tradução diferente e as definições satisfaçam os seguintes requisitos. Dada tal entidade D definida em mais de uma unidade de tradução, para todas as definições de D, [...] os seguintes requisitos devem ser satisfeitos.
[...]
(13.10) — Em cada uma dessas definições, exceto dentro dos argumentos padrão e argumentos modelo padrão de D, as expressões lambda correspondentes devem ter o mesmo tipo de fechamento (veja abaixo).
Agora, podemos aplicar este parágrafo ao meu trecho de código acima
a) tomando D como o modelo de classe (que é uma entidade modelo), em cujo caso (13.10) parece dizer que o argumento de modelo padrão está isento desta regra, ou
b) tomando D como o argumento de modelo padrão, ao qual esta regra deve ser aplicada. O "veja abaixo" no final da citação se refere, presumo, ao ponto 14:
Se D for um modelo e for definido em mais de uma unidade de tradução, os requisitos precedentes devem ser aplicados tanto aos nomes do escopo envolvente do modelo usados na definição do modelo (13.8.3), quanto aos nomes dependentes no ponto de instanciação (13.8.2). Esses requisitos também se aplicam às entidades correspondentes definidas dentro de cada definição de D (incluindo os tipos de fechamento de expressões lambda, mas excluindo entidades definidas dentro de argumentos padrão ou argumentos de modelo padrão de D ou uma entidade não definida dentro de D). Para cada uma dessas entidades e para o próprio D, o comportamento é como se houvesse uma única entidade com uma única definição, incluindo na aplicação desses requisitos a outras entidades. [Nota: A entidade ainda é declarada em várias unidades de tradução, e 6.6 ainda se aplica a essas declarações. Em particular, as expressões lambda (7.5.5) que aparecem no tipo de D podem resultar em diferentes declarações tendo tipos distintos, e as expressões lambda que aparecem em um argumento padrão de D ainda podem denotar tipos diferentes em diferentes unidades de tradução. — nota final]
do qual eu entendo: se D é minha classe de modelo, o argumento de modelo padrão está isento desta regra. Mas então a nota no final continua especificando que a expressão lambda no argumento de modelo padrão pode ter tipos diferentes em TUs diferentes, portanto, presumo, quebrando ODR.
Edição 2: muito relacionado, mas ainda não consigo chegar a uma conclusão final:
Significado da observação sobre itens definidos várias vezes
As expressões lambda que aparecem em diferentes definições de uma mesma entidade produzem o mesmo tipo de fechamento?
Sim, você obteria uma violação de ODR neste caso, e geralmente é IFNDR, exceto no caso de módulo nomeado mencionado em [basic.def.odr]/15.
[basic.def.odr]/1.7 afirma que argumentos de modelo padrão são um dos tipos de item definível e [basic.def.odr]/15 requer múltiplas definições de um item definível para ser "o mesmo". Entretanto, cada expressão lambda produz um tipo distinto, incluindo o mesmo lambda escrito da mesma forma em duas unidades de tradução diferentes. Há situações em que um lambda tem o mesmo tipo em duas TUs porque ele é parte de uma definição envolvente:
Isso ocorre somente porque [basic.def.odr]/17 permite que múltiplas definições de um item definível se comportem como se houvesse uma única definição no programa. No caso de
foo
, uma única definição em todas as TUs implica um único tipo de fechamento lambda em todas as TUs.Essa unificação se aplica ao modelo de classe do OP? Não, porque [basic.def.odr]/17 tem um carve-out para argumentos padrão e argumentos de modelo padrão:
Tomando
D
como modelo de classeMyType
, vemos que o argumento de modelo padrão para seu parâmetro de modelo (sem nome) é uma entidade excluída, então o comportamento não é como se houvesse apenas uma única definição do argumento padrão em todo o programa.Por outro lado, tomando
D
como definição de argumento padrão, vemos que [basic.def.odr]/15 é violado porque o item 15.6 requer:Porque
D
neste caso é o argumento de modelo padrão em si, ele não tem nenhum argumento de modelo padrão próprio (D
afinal, não é um modelo em si), então não pode se beneficiar da exceção neste marcador. A expressão lambda deve ser a mesma em todas as definições. Porque /15 é violado,D
não pode se beneficiar de /17, é apenas uma violação de ODR.Um dos exemplos na p18 usa um argumento de função padrão em vez de um argumento de modelo padrão:
O texto explicativo afirma que definir
g
em múltiplas TUs causa uma violação de ODR porque cada lambda tem um tipo diferente. Como argumentos de função padrão são tratados da mesma forma que argumentos de modelo padrão para os propósitos do ODR, o exemplo do OP foi claramente concebido para também ser uma violação de ODR.