I need to define a C++ template that accepts several 3D coordinates as their parameters. When all dimensions of these coordinates are defined as separate integer variables, the parameter list would become exceedingly long - 3 coordinates need 9 parameters, which makes the template hard to use.
Thus, it's highly desirable to declare the templates in a way to use compile-time arrays. Their default arguments should also be declared directly at the location of the template declaration as values, rather than as variable names.
After some experimentation, to my surprise, I found GCC 13 will accept the following C++ program with 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;
}
However, clang 18 rejects the braced-init-list as invalid:
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.
Question
Is it really a legal C++ program? If it is, what syntax should I use to convince clang to accept it? If it's not, how can I fix the code (and should I report a GCC bug for accepting it unquestionably)?
{}
. Does clang acceptstd::array<int, 3> offset = std::array<int, 3>{}
? – Pillowstd::array<int, 3> offset = std::array<int, 3>{0, 0, 0}
works!Array<{1, 1, 1}> arr;
also needs to beArray<std::array<int, 3>{1, 1, 1}> arr;
. – Omidyarstd::array
before the braced init list. – Librevilleposition_t { int x; int y; int z; }
is semantically stronger. Now you can also have structvelocity_t
and you can't mix up position and velocity at compile time. Also your code becomes more readable as a result (std::array is pretty meaningless) – Joijoice