Preciso definir um modelo C++ que aceite várias coordenadas 3D como parâmetros. Quando todas as dimensões destas coordenadas são definidas como variáveis inteiras separadas, a lista de parâmetros se tornaria excessivamente longa - 3 coordenadas precisam de 9 parâmetros, o que torna o modelo difícil de usar.
Portanto, é altamente desejável declarar os modelos de forma a usar matrizes em tempo de compilação. Seus argumentos padrão também devem ser declarados diretamente no local da declaração do modelo como valores, em vez de nomes de variáveis.
Após algumas experiências, para minha surpresa, descobri que o GCC 13 aceitará o seguinte programa C++ com std=c++20
:
#include <cstdio>
#include <array>
template <
std::array<int, 3> offset = {0, 0, 0}
>
struct Array
{
void operator() (int i, int j, int k)
{
printf("(%d, %d, %d)\n", i + offset[0], j + offset[1], k + offset[2]);
}
};
int main(void)
{
Array arr_default;
arr_default(0, 0, 0);
Array<{1, 1, 1}> arr;
arr(0, 0, 0);
return 0;
}
No entanto, o clang 18 rejeita a lista de inicialização com chaves como inválida:
test2.cpp:5:30: error: expected expression
5 | std::array<int, 3> offset = {0, 0, 0}
| ^
test2.cpp:17:8: error: no viable constructor or deduction guide for deduction of template arguments of 'Array'
17 | Array arr_default;
| ^
test2.cpp:7:8: note: candidate template ignored: couldn't infer template argument 'offset'
7 | struct Array
| ^
test2.cpp:7:8: note: candidate function template not viable: requires 1 argument, but 0 were provided
7 | struct Array
| ^~~~~
test2.cpp:20:8: error: expected expression
20 | Array<{1, 1, 1}> arr;
| ^
3 errors generated.
Pergunta
É realmente um programa C++ legal? Se for, que sintaxe devo usar para convencer o clang a aceitá-lo? Caso contrário, devo relatar um bug do GCC por aceitá-lo inquestionavelmente?
Existe uma forma alternativa e mais compatível de atingir meus objetivos? O uso
std::array
não é necessário, quaisquer outros métodos com efeito equivalente também são aceitáveis.
Problema
Este é o CWG 2450 e/ou CWG 2049 e , embora a gramática atual não permita isso, propõe-se que seja permitido/válido pelo motivo mencionado abaixo. Isso significa que o Gcc está apenas permitindo preventivamente a sintaxe . Do CWG 2450:
(ênfase minha)
Caso você esteja se perguntando como a gramática atual não permite isso, em temp.name#1 :
E como
{1, 1, 1}
não é nenhuma das três construções listadas acima, não pode ser usado como argumento de modelo de acordo com as regras gramaticais atuais.Solução
Você pode escrever explicitamente
std::array
antes da lista de inicialização entre chaves, conforme mostrado abaixo:Observação
Observe também que o clang trunk também começa a aceitar o programa enquanto o gcc e o msvc já o aceitam em versões anteriores.
No C++ atual, eu esperaria que seu código fosse parecido com isto: