为什么在聚合推导中不支持括号init列表,而支持括号省略



为什么在聚合推导中不支持括号init列表,而支持括号省略?

#include <iostream>
template<typename T>
struct Test{
T t[2];
};
int main(){
Test t{{1,2}};  // #1
// Test t1{1,2} // #2
}

CCD_ 1被GCC拒绝,而CCD_。

根据超过匹配等级扣除#1

此外,如果定义了C,并且它的定义满足聚合类([dcl.init.agr](的条件,假设任何依赖基类都没有虚拟函数和虚拟基类,并且初始化器是一个非空的带括号的init列表或带括号的表达式列表,并且没有C的推导指南,该集合包含一个额外的函数模板,称为聚合推断候选者,定义如下。设X1,。。。,XN是初始值设定项列表的元素,或者是支持的初始值设定值列表的指定初始值设定者列表,或者是表达式列表的元素。对于每个Xi,设ei是C或其一个(可能是递归的(子集合的相应聚合元素,如果

  • [1.5]大括号省略不适用于具有依赖非数组类型或具有值依赖绑定的数组类型的任何聚合元素,并且
  • [1.6]假设作为包扩展的每个非尾随聚合元素不对应于初始值设定项列表的元素,并且
  • [1.7]假设作为包扩展的尾随聚合元素对应于初始值设定项列表的所有剩余元素(如果有的话(

如果对于任何Xi没有这样的聚合元素ei,则不将聚合扣除候选者添加到集合中。如上所述,从假设的构造函数C(T1,…,Tn(中推导出聚合推断候选者

  • 如果ei是数组类型,x是支持的init列表或字符串文字,则T<sub〉i>是对ei声明类型的右值引用

在我的例子中,x1是一个支持的初始化列表({1,2}(,而e1的类型是数组类型T[2],因此构造函数应该是C(T(&&)[2])的形式,并且可以根据temp.dexecute从{1,2}推导出T(&&)[2]的模板参数。调用#1

为什么GCC拒绝了上面的例子?GCC却接受括号省略的方式?如何解释这个例子?这被认为是GCC的错误还是我误解了什么?


另一个我认为很奇怪的问题是,如果XI是一个本应用于初始化子集合的支持初始化列表,如果bullet[1.5]为true,那么XI

更新

在p2082r1中进一步挖掘后。从上下文来看,aggregate元素似乎意味着聚合类型的元素,而不是聚合的元素。IIUC,如果满足项目符号[1.5]、[1.6]、[1.7],则ei将是聚合元素。然而,如果这些子弹都不一致,那么ei会是什么?这里似乎没有详细说明。

在P2082r1中进一步挖掘,我认为GCC在这个例子中是正确的。由于Test的子集合T t[2]具有非依赖值界的数组,因此相应的e0和e1

当本指南用作假设类类型的构造函数以参与重载解析时,由于初始值设定项是#12,因此此处应用[over.match.list],由于没有初始值设定值列表构造函数,因此如上所述,初始值设定项列表的元素用作此处的参数,候选template<typename T> Test(T, T)有两个参数,但只有一个参数({1,2}(提供,因此过载解决方案失败,因此程序格式错误。

然而,我仍然认为这里的规则不明确,应该加以改进,使其含义更加明确。

这是GCC 11.2版本之前的一个错误,并在GCC 11.3中修复。看见https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101344以获取导致此错误的详细解释。

即使是GCC的早期版本也可以编译类似甚至更困难的案例A(正如在问题评论中提到的(:

template<typename T, int N>
struct A { T t[N]; };
template<typename T>
struct B { T t[2]; };
int main()
{
[[maybe_unused]] A a{{1, 2}}; //ok in GCC
[[maybe_unused]] B b{{1, 2}}; //ok in GCC >= 11.3
}

演示:https://gcc.godbolt.org/z/4rcYj6fah

最新更新