Há não muito tempo, expressões de requerimento (a frase introduzida pelo segundo requer) não era permitida em expressões de restrição (a frase introduzida pelo primeiro requer). Só poderia aparecer nas definições de conceito. De fato, é exatamente isso que é proposto na seção desse artigo, onde essa alegação aparece.
No entanto, em 2016, houve uma proposta para relaxar essa restrição [nota do editor: P0266 ]. Observe a tacada do parágrafo 4 na seção 4 do documento. E assim nasceu requer requer.
Para dizer a verdade, eu nunca havia implementado essa restrição no GCC, portanto sempre foi possível. Eu acho que Walter pode ter descoberto isso e achou útil, levando a esse artigo.
Para que ninguém pense que eu não era sensível à escrita exige duas vezes, passei algum tempo tentando determinar se isso poderia ser simplificado. Resposta curta: não.
O problema é que existem duas construções gramaticais que precisam ser introduzidas após uma lista de parâmetros do modelo: muito comumente uma expressão de restrição (como P && Q
) e ocasionalmente requisitos sintáticos (como requires (T a) { ... }
). Isso é chamado de expressão requer.
O primeiro requer introduz a restrição. O segundo requer introduz a expressão requer. É assim que a gramática compõe. Não acho nada confuso.
Eu tentei, em um ponto, recolhê-los para um único requerimento. Infelizmente, isso leva a alguns problemas de análise seriamente difíceis. Você não pode dizer com facilidade, por exemplo, se a (
after the require denota uma subexpressão aninhada ou uma lista de parâmetros. Não acredito que exista uma desambiguação perfeita dessas sintaxes (veja a justificativa para a sintaxe de inicialização uniforme; esse problema também existe).
Então você faz uma escolha: make exige a introdução de uma expressão (como agora) ou a introdução de uma lista parametrizada de requisitos.
Eu escolhi a abordagem atual porque, na maioria das vezes (em quase 100% das vezes), quero algo diferente de uma expressão de necessidade. E, no caso extremamente raro, eu queria uma expressão requerida para restrições ad hoc, realmente não me importo de escrever a palavra duas vezes. É um indicador óbvio que eu não desenvolvi uma abstração suficientemente sólida para o modelo. (Porque se eu tivesse, teria um nome.)
Eu poderia ter escolhido fazer com que os requisitos introduzam uma expressão de requisitos. Na verdade, isso é pior, porque praticamente todas as suas restrições começam a ficar assim:
template<typename T>
requires { requires Eq<T>; }
void f(T a, T b);
Aqui, o segundo requisito é chamado de requisito aninhado; avalia sua expressão (outro código no bloco da expressão de necessidade não é avaliado). Eu acho que isso é muito pior do que o status quo. Agora, você começa a escrever requer duas vezes em todos os lugares.
Eu também poderia ter usado mais palavras-chave. Este é um problema por si só --- e não é apenas uma troca de bicicletas. Pode haver uma maneira de "redistribuir" as palavras-chave para evitar a duplicação, mas não pensei muito nisso. Mas isso realmente não muda a essência do problema.
noexcept(noexcept(...))
.