c++ - 为什么聚合推导中不支持大括号初始化列表但支持大括号省略?

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

为什么聚合推导中不支持大括号初始化列表但支持大括号省略?

#include <iostream>
template<typename T>
struct Test{
    T t[2];
};
int main(){
  Test t{{1,2}};  // #1
  // Test t1{1,2} // #2
}
#1rejected通过 GCC 而 #2将被 GCC 接受。
根据 over.match.class.deduct#1

In addition, if C is defined and its definition satisfies the conditions for an aggregate class ([dcl.init.aggr]) with the assumption that any dependent base class has no virtual functions and no virtual base classes, and the initializer is a non-empty braced-init-list or parenthesized expression-list, and there are no deduction-guides for C, the set contains an additional function template, called the aggregate deduction candidate, defined as follows. Let X1,...,XN be the elements of the initializer-list or designated-initializer-list of the braced-init-list, or of the expression-list. For each Xi, let ei be the corresponding aggregate element of C or of one of its (possibly recursive) subaggregates that would be initialized by Xi if

  • [1.5] brace elision is not considered for any aggregate element that has a dependent non-array type or an array type with a value-dependent bound, and
  • [1.6] each non-trailing aggregate element that is a pack expansion is assumed to correspond to no elements of the initializer list, and
  • [1.7] a trailing aggregate element that is a pack expansion is assumed to correspond to all remaining elements of the initializer list (if any).


If there is no such aggregate element ei for any Xi, the aggregate deduction candidate is not added to the set. The aggregate deduction candidate is derived as above from a hypothetical constructor C(T1,...,Tn)

  • if ei is of array type and xi is a braced-init-list or string-literal, Ti is an rvalue reference to the declared type of ei


在我的例子中,x1 是一个支撑初始化列表({1,2}),e1 的类型是数组类型 T[2],因此构造函数应该是形式 C(T(&&)[2])并且模板参数可以推导出 T(&&)[2]来自 {1,2}根据 temp.deduct.call#1
为什么上面的例子被 GCC 拒绝了? GCC 而接受括号省略方式?如何解释这个例子?这被认为是 GCC 的错误还是我误解的东西?

另一个我认为很奇怪的问题是,如果 Xi 是一个应该用于初始化子聚合的支撑初始化列表,如果 bullet [1.5] 为真,那么 Xi 将用于初始化子聚合的元素。这是什么意思?
更新
p2082r1 中进一步挖掘后.从它的上下文来看,似乎是聚合元素表示聚合类型的元素而不是聚合的元素。 IIUC,如果子弹[1.5],[1.6],[1.7]满足,ei将是聚合元素。但是,如果这些子弹都不符合,那么ei会是什么?这里似乎没有指定。

最佳答案

P2082r1 中进一步挖掘,我认为 GCC 在这个例子上是正确的。由于子聚合T t[2]Test有一个非依赖值边界数组,因此对应的 e0 和 e1 是 t0 , t1 , 分别。因此,派生指南是 template<typename T> Test(T, T) .
当本指南用作假设类类型的构造函数以参与重载解析时,此处应用 [over.match.list],因为初始值设定项为 {{1,2}} ,由于没有初始化列表构造函数,初始化列表的元素在这里用作参数,如前所述,候选template<typename T> Test(T, T)有两个参数,但只有一个参数( {1,2} )提供,因此重载决议失败,因此程序格式错误。
但是,我仍然认为这里的规则不明确,应该改进以使其含义更明确。

关于c++ - 为什么聚合推导中不支持大括号初始化列表但支持大括号省略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67280884/

相关文章:

c++ - std::chrono::from_stream gcc 可用性,在 gcc 10.1.0 中不可用

C++ 通用链表和迭代器

C++:不寻常的运算符重载

c++ - 在不使用嵌套名称说明符的情况下定义 namespace 的成员的 clang 中是否存在错误

c++ - 这是 "elision failure"语言强制要求的吗?

c++ - 我可以 co_await 一个 io_context 在协程中由另一个在 Asio 中执行的操作吗?

c++ - 如何定义任意 std::vector 满足的概念?

c++ - 推导引用模板参数的类型

c++ - (Qt) 如何检查 QTextEdit 小部件文本是否从 QTabWidget 更改

c - 结构赋值是否保证填充也相等