从 std::array 私有继承时无法从 std::initializer_list 构造
Can't construct from std::initializer_list when privately inheriting from std::array
我正在尝试制作 std::array 的包装器以按照 的建议执行边界检查。这是我的代码:
template <typename T, size_t N>
class Array : private std::array<T, N> {
public:
using std::array<T, N>::array;
T operator[](size_t i) {
return this->at(i);
}
T operator[](size_t i) const {
return this->at(i);
}
};
int main() {
Array<int, 3> arr = {0,0,0};
}
当我尝试 运行 时,出现以下错误:error: no matching constructor for initialization of 'Array<int, 3>'
。
如果我省略行 using std::array<T, N>::array;
并公开继承它,代码可以工作,但不建议使用此选项。
我在这里错过了什么?为什么我的 class 不能创建这样的实例?
提前致谢!
std::array
结构未实现采用 initializer_list
的构造函数。它实际上只有一个隐式定义的构造函数。 std::array
,per [array.cons]
,确实满足聚合条件,因此可以通过 {1,2,3}
初始化。
指定的聚合要求(来自[dcl.init.aggr]/1.4
)
no virtual, private, or protected base classes
因此,您的 class 不适用于 private
基础 class。
请注意,即使您将基数设为 class public
,您最终也会违反 [dcl.init.aggr]/1.1
,即
no user-provided, explicit, or inherited constructors
所以你必须删除你的 using
语句。
有关工作示例,请参阅 here。
std::array
被设计为聚合。它没有用户提供的构造函数,因此可以使用聚合初始化对其进行初始化。因为你的 Array
class 有一个私有基 class,所以它 不是 聚合,只能由构造函数初始化。
另一种看待它的方式是,由于 Array
具有对用户隐藏的成员,因此语言允许用户使用聚合语法直接初始化这些元素是没有意义的,初始化普通数组的方式。相反,用户必须调用构造函数,其中 Array
class 的作者已明确实施必要的初始化逻辑来履行 Array
class 的合同。
一个简单的解决方案是使 std::array
基础 class public。如果你不想这样做,你可以编写自己的 initializer_list
构造函数,但这很棘手且不完美:
// delegate to a helper constructor
Array(std::initializer_list<T> il) : Array(il, std::make_index_sequence<N>{}) {}
private:
template <size_t... i>
Array(std::initializer_list<T> il, std::index_sequence<i...>)
: std::array<T, N>{(i < il.size() ? il.begin()[i] : T{})...} {}
辅助构造函数使用初始化列表中的一个元素来初始化相应的 std::array
元素(如果存在);否则,它从 T{}
.
初始化它
这个的主要问题是,如果 T
是一个不能被值初始化的 class,那么即使 N
也不能调用这个 Array
构造函数提供了初始值设定项,因为编译器无法在编译时强制执行“il
包含 N
元素”条件,因此必须假设 T{}
可以在运行时调用。没有办法完美地模拟聚合初始化。
我正在尝试制作 std::array 的包装器以按照
template <typename T, size_t N>
class Array : private std::array<T, N> {
public:
using std::array<T, N>::array;
T operator[](size_t i) {
return this->at(i);
}
T operator[](size_t i) const {
return this->at(i);
}
};
int main() {
Array<int, 3> arr = {0,0,0};
}
当我尝试 运行 时,出现以下错误:error: no matching constructor for initialization of 'Array<int, 3>'
。
如果我省略行 using std::array<T, N>::array;
并公开继承它,代码可以工作,但不建议使用此选项。
我在这里错过了什么?为什么我的 class 不能创建这样的实例?
提前致谢!
std::array
结构未实现采用 initializer_list
的构造函数。它实际上只有一个隐式定义的构造函数。 std::array
,per [array.cons]
,确实满足聚合条件,因此可以通过 {1,2,3}
初始化。
指定的聚合要求(来自[dcl.init.aggr]/1.4
)
no virtual, private, or protected base classes
因此,您的 class 不适用于 private
基础 class。
请注意,即使您将基数设为 class public
,您最终也会违反 [dcl.init.aggr]/1.1
,即
no user-provided, explicit, or inherited constructors
所以你必须删除你的 using
语句。
有关工作示例,请参阅 here。
std::array
被设计为聚合。它没有用户提供的构造函数,因此可以使用聚合初始化对其进行初始化。因为你的 Array
class 有一个私有基 class,所以它 不是 聚合,只能由构造函数初始化。
另一种看待它的方式是,由于 Array
具有对用户隐藏的成员,因此语言允许用户使用聚合语法直接初始化这些元素是没有意义的,初始化普通数组的方式。相反,用户必须调用构造函数,其中 Array
class 的作者已明确实施必要的初始化逻辑来履行 Array
class 的合同。
一个简单的解决方案是使 std::array
基础 class public。如果你不想这样做,你可以编写自己的 initializer_list
构造函数,但这很棘手且不完美:
// delegate to a helper constructor
Array(std::initializer_list<T> il) : Array(il, std::make_index_sequence<N>{}) {}
private:
template <size_t... i>
Array(std::initializer_list<T> il, std::index_sequence<i...>)
: std::array<T, N>{(i < il.size() ? il.begin()[i] : T{})...} {}
辅助构造函数使用初始化列表中的一个元素来初始化相应的 std::array
元素(如果存在);否则,它从 T{}
.
这个的主要问题是,如果 T
是一个不能被值初始化的 class,那么即使 N
也不能调用这个 Array
构造函数提供了初始值设定项,因为编译器无法在编译时强制执行“il
包含 N
元素”条件,因此必须假设 T{}
可以在运行时调用。没有办法完美地模拟聚合初始化。