问题
For anyone stumbling upon this question in the future, the original question was: "How to get the simplest example (Point) from this article to compile with GCC or CLANG?"
- Edit 1 shows the smallest possible code that fails with CLANG but compiles with GCC (both with -std=c++2a).
- Edit 2 shows further code added, that breaks GCC as well.
The author of the article (@BarryRevzin) was kind enough to comment the reason why this won't work yet, thank you Barry!
Edit 1:
Simplified code below works with gcc 9.3.0 but not with clang 10.0.0:
struct Point {
int x = 0;
int y = 0;
};
template <Point> // ok in C++20
void takes_tmpl_point();
int main()
{
// EMPTY
}
Edit 2:
The original code, as per the author, won't work on GCC or CLANG as of yet due to the compilers being behind the standard a bit. Original code below:
struct Point {
int x = 0;
int y = 0;
};
template <Point> // ok in C++20
void takes_tmpl_point();
int main()
{
takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2
}
This will result in the following compilation error on GCC 9.3:
test.cpp: In function ‘int main()’:
test.cpp:11:35: error: no matching function for call to ‘takes_tmpl_point<{1, 2}>()’
11 | takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2
| ^
test.cpp:7:6: note: candidate: ‘template<Point <anonymous> > void takes_tmpl_point()’
7 | void takes_tmpl_point();
| ^~~~~~~~~~~~~~~~
test.cpp:7:6: note: template argument deduction/substitution failed:
test.cpp:11:35: error: could not convert ‘{1, 2}’ from ‘<brace-enclosed initializer list>’ to ‘Point’
11 | takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2
| ^
And the following error on clang 10.0.0:
test.cpp:6:16: error: a non-type template parameter cannot have type 'Point'
template <Point> // ok in C++20
^
test.cpp:11:21: error: expected expression
takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2
^
2 errors generated.
Compilers used:
- clang: clang version 10.0.0-4ubuntu1
- gcc: gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
回答1:
Clang just doesn't implement class types as non-type template parameters yet, see P1907 in this table.
gcc does implement them but there's actually an issue here. The grammar for template-argument doesn't actually allow for a braced-init-list. This is a clear language defect (there was never a reason to have such a thing before P1907 but now there's certainly no reason to not have it). This is a language bug at the moment. Nevertheless, gcc went ahead and does support a braced-init-list as a template argument... just not a designated-initializer-list.
So that blog post of mine is running ahead of the actual language by a bit... Until the language catches up, even though this is technically unsupported:
takes_tmpl_point<{.x=1, .y=2}>();
This is definitely valid:
takes_tmpl_point<Point{.x=1, .y=2}>();
来源:https://stackoverflow.com/questions/61940342/a-non-type-template-parameter-cannot-have-type