非类型模板参数不能有类型

Fer*_*ymo 1 c++ c++20

对于将来遇到这个问题的任何人来说,最初的问题是:“如何从本文中获取最简单的示例(点)使用GCCCLANG进行编译?”

\n\n
    \n
  • 编辑 1 显示了使用 CLANG 失败但使用 GCC 编译的最小可能代码(均使用 -std=c++2a)。
  • \n
  • 编辑 2 显示了添加的更多代码,这也破坏了 GCC。
  • \n
\n\n

文章的作者(@BarryRevzin)很友善地评论了为什么这还不起作用的原因,谢谢巴里!

\n\n

编辑1:

\n\n

下面的简化代码适用于 gcc 9.3.0,但不适用于 clang 10.0.0:

\n\n
struct Point {                                                                                                                                                                               \n   int x = 0;                                                                                                                                                                                \n   int y = 0;                                                                                                                                                                                \n};                                                                                                                                                                                           \n\ntemplate <Point> // ok in C++20                                                                                                                                                              \nvoid takes_tmpl_point();                                                                                                                                                                     \n\nint main()                                                                                                                                                                                   \n{\n    // EMPTY\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑2:

\n\n

根据作者的说法,由于编译器稍微落后于标准,原始代码目前还无法在 GCC 或 CLANG 上运行。原始代码如下:

\n\n
struct Point {                                                                                                                                                                               \n   int x = 0;                                                                                                                                                                                \n   int y = 0;                                                                                                                                                                                \n};                                                                                                                                                                                           \n\ntemplate <Point> // ok in C++20                                                                                                                                                              \nvoid takes_tmpl_point();                                                                                                                                                                     \n\nint main()                                                                                                                                                                                   \n{                                                                                                                                                                                            \n   takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

这将导致 GCC 9.3 上出现以下编译错误:

\n\n
test.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\ntest.cpp:11:35: error: no matching function for call to \xe2\x80\x98takes_tmpl_point<{1, 2}>()\xe2\x80\x99\n   11 |    takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2\n      |                                   ^\ntest.cpp:7:6: note: candidate: \xe2\x80\x98template<Point <anonymous> > void takes_tmpl_point()\xe2\x80\x99\n    7 | void takes_tmpl_point();\n      |      ^~~~~~~~~~~~~~~~\ntest.cpp:7:6: note:   template argument deduction/substitution failed:\ntest.cpp:11:35: error: could not convert \xe2\x80\x98{1, 2}\xe2\x80\x99 from \xe2\x80\x98<brace-enclosed initializer list>\xe2\x80\x99 to \xe2\x80\x98Point\xe2\x80\x99\n   11 |    takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2\n      |                                   ^\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

在 clang 10.0.0 上出现以下错误:

\n\n
test.cpp:6:16: error: a non-type template parameter cannot have type \'Point\'\ntemplate <Point> // ok in C++20\n               ^\ntest.cpp:11:21: error: expected expression\n   takes_tmpl_point<{.x=1, .y=2}>(); // x=1, y=2\n                    ^\n2 errors generated.\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用的编译器:

\n\n
    \n
  • clang:clang版本10.0.0-4ubuntu1
  • \n
  • gcc:gcc(Ubuntu 9.3.0-10ubuntu2)9.3.0
  • \n
\n

Bar*_*rry 6

Clang 只是还没有将类类型实现为非类型模板参数,请参阅此表中的 P1907 。

gcc 确实实现了它们,但这里实际上存在一个问题。template-argument的语法实际上不允许使用braced-init-list这是一个明显的语言缺陷(在P1907之前从来没有理由有这样的东西,但现在肯定没有理由没有它)。目前这是一个语言错误。尽管如此,gcc 仍然支持用braced-init-list作为模板参数……只是不支持designated-initializer-list

因此,我的博客文章比实际语言领先了一点......直到语言赶上,即使这在技术上不受支持:

takes_tmpl_point<{.x=1, .y=2}>(); 
Run Code Online (Sandbox Code Playgroud)

这绝对是有效的:

takes_tmpl_point<Point{.x=1, .y=2}>();
Run Code Online (Sandbox Code Playgroud)