简体   繁体   English

从 std::array 私有继承时无法从 std::initializer_list 构造

[英]Can't construct from std::initializer_list when privately inheriting from std::array

I'm trying to make a wrapper of std::array to perform boundary checks as suggested by this answer .我正在尝试制作 std::array 的包装器,以按照此答案的建议执行边界检查。 This is the code I have:这是我的代码:

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};
}

When I try to run it I get the following error: error: no matching constructor for initialization of 'Array<int, 3>' .当我尝试运行它时,出现以下错误: error: no matching constructor for initialization of 'Array<int, 3>'

If I omit the line using std::array<T, N>::array;如果我using std::array<T, N>::array;省略该行and inherit it publicly the code works, though this option is not advisable.并公开继承它的代码工作,虽然这个选项是不可取的。

What am I missing here?我在这里想念什么? Why can't my class create an instance like this?为什么我的 class 不能创建这样的实例?

Thanks in advance!提前致谢!

The std::array struct does not implement a constructor which takes an initializer_list . std::array结构没有实现采用initializer_list的构造函数。 It actually only has an implicitly defined constructor.它实际上只有一个隐式定义的构造函数。 std::array , per [array.cons] , does meet the conditions for aggregate though, so it can be initialized via {1,2,3} for example.每个[array.cons]std::array确实满足聚合的条件,因此可以通过例如{1,2,3}对其进行初始化。

The requirements for aggregates specified (from [dcl.init.aggr]/1.4 )指定聚合的要求(来自[dcl.init.aggr]/1.4

no virtual, private, or protected base classes没有虚拟、私有或受保护的基类

Therefore, your class will not work with a private base class.因此,您的 class 将无法与private基础 class 一起使用。

Note that even if you make the base class public , you end up violating [dcl.init.aggr]/1.1 , which states请注意,即使您将基础 class 设为public ,您最终也会违反[dcl.init.aggr]/1.1 ,其中指出

no user-provided, explicit, or inherited constructors没有用户提供的、显式的或继承的构造函数

So you would have to get rid of your using statement.所以你必须摆脱你的using声明。

See here for a working example.有关工作示例,请参见此处

std::array is designed to be an aggregate. std::array被设计为一个聚合。 It has no user-provided constructors, so one can initialize it using aggregate initialization.它没有用户提供的构造函数,因此可以使用聚合初始化对其进行初始化。 Because your Array class has a private base class, it is not an aggregate, and can only be initialized by a constructor.因为您的Array class 有一个私有基 class,所以它不是聚合,只能由构造函数初始化。

Another way of looking at it is that since Array has members that are hidden from the user, it does not make sense for the language to allow the user to directly initialize those elements using the aggregate syntax, the way one might initialize a normal array.另一种看待它的方式是,由于Array具有对用户隐藏的成员,因此语言允许用户使用聚合语法直接初始化这些元素是没有意义的,就像初始化普通数组的方式一样。 Instead the user must call a constructor, wherein the Array class's author has explicitly implemented the necessary initialization logic to fulfill the Array class's contract.相反,用户必须调用构造函数,其中Array类的作者已经明确实现了必要的初始化逻辑来履行Array类的契约。

One simple solution is to make the std::array base class public.一种简单的解决方案是将std::array基础 class 公开。 If you don't want to do that, you can write your own initializer_list constructor, but it's tricky and imperfect:如果您不想这样做,您可以编写自己的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{})...} {}

The helper constructor uses an element from the initializer list to initialize the corresponding std::array element, if one exists;辅助构造函数使用初始值设定项列表中的一个元素来初始化相应的std::array元素(如果存在); otherwise, it initializes it from T{} .否则,它从T{}初始化它。

The main problem with this is that if T is a class that cannot be value-initialized, then this Array constructor cannot be called even if N initializers are supplied, because the compiler cannot enforce the " il contains N elements" condition at compile time, and thus must assume that T{} may be called at runtime.这样做的主要问题是,如果T是无法进行值初始化的 class,那么即使提供了N个初始化器,也无法调用此Array构造函数,因为编译器无法在编译时强制执行“ il contains N elements”条件,因此必须假设T{}可以在运行时调用。 There is no way to perfectly emulate aggregate initialization.没有办法完美地模拟聚合初始化。

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

相关问题 不匹配运算符 &#39;=&#39; (std::array<T, 3> 和 std::initializer_list<T> ) - no match for operator '=' (std::array<T, 3> and std::initializer_list<T>) 从 std::initializer_list 派生是否合法? - Is it legal to derive from std::initializer_list? 是否可以以编程方式构造std :: initializer_list? - Is it possible to programmatically construct a std::initializer_list? std :: initializer_list作为std :: array构造函数 - std::initializer_list as std::array constructor 我们不能从initializer_list创建std :: array,但是可以使用带有可变参数的辅助函数来创建它吗? - We cannot create an std::array from an initializer_list, but can we create it with a helper function with variadic arguments? 无法从std :: initializer_list <int>构造std :: initializer_list <int const> - std::initializer_list<int const> cannot be constructed from std::initializer_list<int> 有没有办法从未知数量的 arguments 构造一个 std::initializer_list ? - Is there any way to construct an std::initializer_list from an unknown number of arguments? 我可以假设 std::initializer_list 是作为数组实现的吗 - Can I assume that std::initializer_list is implemented as an array Clang为什么不能优化std :: initializer_list? - Why can't Clang optimise away std::initializer_list? 将一个initializer_list分配给std :: array - Assigning a initializer_list to std::array
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM