我想做一个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;
并公开继承它的代码,虽然这个选项是不可取的。
我在这里遗漏了什么?为什么我的类不能创建这样的实例?
先谢谢你
该 std::array
结构没有实现一个以 initializer_list
. 实际上它只有一个隐式定义的构造函数。std::array
解释说,每 [array.cons]
不过,它确实符合集合的条件,所以可以通过 {1,2,3}
例如:
所规定的对集合体的要求(从 [dcl.init.aggr]/1.4
)
没有虚拟的、私有的或受保护的基类
因此,你的班级将无法与 private
基类。
注意,即使你把基类做成 public
,你最终违反了 [dcl.init.aggr]/1.1
其中指出
没有用户提供的、显式的或继承的构造函数。
所以你必须摆脱你的 using
声明。
见 此处 的工作实例。
std::array
被设计成一个集合。它没有用户提供的构造函数,所以可以使用聚合初始化来初始化它。因为你的 Array
类有一个私有基类,它是 不 的集合,并且只能由构造函数初始化。
另一种看法是,由于 Array
的成员是对用户隐藏的,因此,语言不允许用户使用聚合语法直接初始化这些元素,就像初始化一个普通数组一样,是没有意义的。相反,用户必须调用一个构造函数,其中的 Array
类的作者已经明确地实现了必要的初始化逻辑,以满足 Array
类的合同。
一个简单的解决方案是将 std::array
基类公共。如果你不想这样做,你可以写你自己的 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
是一个不能进行值初始化的类,那么这个 Array
构造函数不能被调用,即使 N
提供了初始化器,因为编译器不能执行"il
包含 N
元素 "的条件,因此必须假定 T{}
可以在运行时被调用。没有办法完美地模拟集合初始化。