【问题标题】:Class type non-type template parameter initialization does not compile类类型非类型模板参数初始化不编译
【发布时间】:2021-02-18 12:44:43
【问题描述】:

我的印象是,在新的 C++20 标准下,以下代码应该成为有效代码:

struct Foo
{
  int a, b;
};

template<Foo>
struct Bar
{};

Bar<{.a=1, .b=2}> bar;

然而,gcc 10.2.0-std=c++20 设置抱怨:could not convert ‘{1, 2}’ from ‘&lt;brace-enclosed initializer list&gt;’ to ‘Foo’ 和 Clang 也无法编译这个 sn-p。有人能指出为什么它的格式不正确吗?

【问题讨论】:

标签: c++ gcc language-lawyer c++20


【解决方案1】:

这个模板参数

{.a=1, .b=2}

根据 template-argument 的语法是不允许的,它只允许以下结构:

模板参数:

常量表达式

类型标识

id-表达式

大括号初始化列表不是上述任何构造,它实际上是initializer,因此不能用作模板参数。

您可以明确说明用作模板参数的对象的类型:

Bar<Foo{.a=1, .b=2}> bar;

这会起作用,因为这是一个常量表达式。

【讨论】:

  • 确实可以编译,但我不明白为什么编译器无法在这里进行推导,并且当bar 是一个接受@ 类型参数的函数时,bar({.a=1, .b=2}) 完全没问题987654329@。你能解释一下为什么这里不能扣除吗?
  • 查看auto&amp;&amp; ref = {.a = 1, .b = 2}; 是否编译。模板参数类型推导和auto&amp;&amp; 类型推导遵循相同的规则。我想它也不会编译,你会更容易弄清楚为什么会这样..
  • @TanveerBadar 我不相信。在 OP 的情况下,没有什么可推断的,没有未知的类型。
  • 似乎只是 c++ 语法不允许这样做:eel.is/c++draft/temp.names#nt:template-argument-list 是模板参数,braced-init-listinitializer,而不是常量表达式。
  • 这是 CWG2450;预计它会在几个月(加上或减去实施时间)内得到修复,大概甚至使用-std=c++20
【解决方案2】:

这是一个 C++ 语法的东西。用于模板参数的东西必须是either type-ids, id-names, or constant-expressions

braced-init-list 不是任何类型的表达式。它们只能在语法上出现在少数地方,特别是那些用于初始化对象或变量的地方。

在过去,它并不真正相关,因为没有太多理由使用花括号初始化列表来初始化少数有效的 NTTP。显然这已经改变了,所以这是一个疏忽。但这就是 C++20 标准所说的。

【讨论】:

    猜你喜欢
    • 2015-10-23
    • 1970-01-01
    • 2021-04-23
    • 2019-11-15
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多