数组的默认初始化与列表初始化的区别

3
我有以下代码,这是一个类似于数组的数据结构的简化版:
template<typename T, size_t N>
struct X
{
    T a[N];

    template<typename... A>
    explicit X(A&&... a) : a{std::forward<A>(a)...} { }  // ERROR (2)
};

int main ()
{
    X<int,3> x;           // OK
    X<X<int,3>,2> y{x,x}; // OK
    X<X<int,3>,2> z;      // ERROR (1)
}

这个代码在clang 3.3和带有-std=c++11选项的gcc 4.8.1上编译正常。现在我尝试升级gcc,所以我尝试使用4.9.0版本。在这种情况下,第三个例子(ERROR(1))实例化了X的构造函数(ERROR(2)),此时编译器报告错误。
error: converting to 'X<int, 3ul>' from initializer list would use explicit
   constructor 'X<T, N>::X(A&&...) [with A = {}; T = int; long unsigned int N = 3ul]

这个例子试图默认初始化数组z及其包含的数组;然而,如果我理解正确,这里的gcc基本上表示,被包含的数组正在通过{}进行列表初始化,但由于构造函数是显式的,因此不允许这样做。
如果我添加以下任一形式的另一个默认构造函数,则错误将消失:
explicit X() {}
explicit X() : a() {}

不是
explicit X() : a{} {}

这个解决方案并不困难,但是你知道谁错了谁对了吗?这样我就知道自己在做什么以及为什么要这么做。


1
最简单的解决方法是添加 X() : a{} {}(去掉 explicit)。我认为这与 http://gcc.gnu.org/PR60416 和 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518 有关。 - Jonathan Wakely
1
我认为这是GCC 4.9的退化,我已经向bugzilla报告了此问题,但正如第1518号问题所示,标准并不真正清楚应该发生什么。 - Jonathan Wakely
@MadScienceDreams 不,使用 std::array<T,N> a; 而不是 T a[N]; 并不会改变任何东西。问题仍然存在。 - iavr
不,我的意思是使用std :: array而不是X。 - IdeaHat
1
从PR60416的链接跳转到http://gcc.gnu.org/PR60417,你会看到原始测试用例已经被修复,但我已经添加了一个新的测试用例作为注释。这是同样的问题。 - Jonathan Wakely
显示剩余11条评论
1个回答

3

这是GCC的一个错误,PR 60417

PR 54835 的早期更改旨在实现C++委员会修复core issue 1518的提议方向。不幸的是,该更改破坏了一些有效的C++03程序,正如PR 60417中的第一个示例所示。已经为PR 60417提交了修复程序,但它只处理了一些情况。具体来说,它无法修复使用显式构造函数初始化类型数组的情况,就像这个问题所示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接