繁体   English   中英

从 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的构造函数。 它实际上只有一个隐式定义的构造函数。 每个[array.cons]std::array确实满足聚合的条件,因此可以通过例如{1,2,3}对其进行初始化。

指定聚合的要求(来自[dcl.init.aggr]/1.4

没有虚拟、私有或受保护的基类

因此,您的 class 将无法与private基础 class 一起使用。

请注意,即使您将基础 class 设为public ,您最终也会违反[dcl.init.aggr]/1.1 ,其中指出

没有用户提供的、显式的或继承的构造函数

所以你必须摆脱你的using声明。

有关工作示例,请参见此处

std::array被设计为一个聚合。 它没有用户提供的构造函数,因此可以使用聚合初始化对其进行初始化。 因为您的Array class 有一个私有基 class,所以它不是聚合,只能由构造函数初始化。

另一种看待它的方式是,由于Array具有对用户隐藏的成员,因此语言允许用户使用聚合语法直接初始化这些元素是没有意义的,就像初始化普通数组的方式一样。 相反,用户必须调用构造函数,其中Array类的作者已经明确实现了必要的初始化逻辑来履行Array类的契约。

一种简单的解决方案是将std::array基础 class 公开。 如果您不想这样做,您可以编写自己的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 contains N elements”条件,因此必须假设T{}可以在运行时调用。 没有办法完美地模拟聚合初始化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM