[英]Default construction of deleted constructor with braced initializer list
Let's say that I want to disable the construction of class, then I can do the following (as per Best style for deleting all constructors (or other function)? ): 假设我想禁用类的构造,那么我可以执行以下操作(根据最佳样式删除所有构造函数(或其他函数)? ):
// This results in Example being CopyConstructible:
struct Example {
Example() = delete;
};
or 要么
struct Example {
template <typename... Ts>
Example(Ts&&...) = delete;
};
or 要么
struct Example {
Example(const Example&) = delete;
};
where the first example can still be copied if constructed (which the intention is to disable), but the second two will disable almost all methods for creating Example
. 如果构造了第一个例子仍然可以被复制(意图是禁用),但是后两个将禁用几乎所有创建Example
方法。 If I default construct any of the above using an empty braced initializer list, then the instance is successfully constructed. 如果我使用空的括号初始化列表默认构造上述任何一个,则成功构造实例。 In Meyer's Effective Modern C++ he gives the example (bottom of page 51): 在Meyer的Effective Modern C ++中,他给出了示例(第51页底部):
Widget w3{}; // calls Widget ctor with no args
which I would thus expect to fail for the above Example
classes ie: 因此,我希望上述Example
类失败,即:
Example e{};
should not construct since it should call the deleted default constructor. 不应该构造,因为它应该调用已删除的默认构造函数。 However, it does, is usable, and if defined as the first case above, is also copyable. 但是,它确实可用,如果定义为上面的第一种情况,也是可复制的。 See live demo . 查看现场演示 。 My question is: Is this correct, and if so, why? 我的问题是:这是正确的,如果是的话,为什么? Also, if this is correct, how do I completely disable the destruction of the class? 另外,如果这是正确的,我如何完全禁用类的销毁?
We will first clarify what it means to initialize an object and how/when/if a constructor is invoked. 我们将首先阐明初始化对象的含义以及如何/何时/是否调用构造函数。
The following is my laymen's interpretation of the standard, for simplicity's sake some irrelevant details have been omitted or mangled. 以下是我的外行人对标准的解释,为简单起见,一些不相关的细节被忽略或破坏。
An initializer is one of the following 初始化程序是以下之一
() // parentheses
// nothing
{} // braced initializer list
= expr // assignment expression
The parentheses and braced initializer list may contain further expressions. 括号和括号初始值设定项列表可能包含更多表达式。
They are used like this, given struct S
给定struct S
,它们就像这样使用
new S() // empty parentheses
S s(1, 2) // parentheses with expression list as (1, 2)
S s // nothing
S s{} // empty braced initializer list
S s{{1}, {2}} // braced initializer list with sublists
S s = 1 // assignment
S s = {1, 2} // assignment with braced initializer list
Note that we have not yet mentioned constructors 请注意,我们还没有提到构造函数
Initialization is performed according to what initializers are used. 根据使用的初始化器执行初始化。
new S() // value-initialize
S s(1, 2) // direct-initialize
S s // default-initialize
S s{} // list-initialize
S s{{1}, {2}} // list-initialize
S s = 1 // copy-initialize
S s = {1, 2} // list-initialize
Once initialization is performed, the object is considered initialized. 一旦执行初始化,就认为该对象已初始化。
Note that, again, constructors have not been mentioned 请注意,同样没有提到构造函数
We will be primarily explaining what it means to list initialize something, as this is the question at hand. 我们将主要解释列出初始化内容的含义,因为这是手头的问题。
When list initialization occurs, the following is considered in order 发生列表初始化时,将按顺序考虑以下内容
An aggregate type is defined as [dcl.init.aggr] 聚合类型定义为[dcl.init.aggr]
An aggregate is an array or a class with 聚合是一个数组或类
-- no user-provided, explicit, or inherited constructors - 没有用户提供的,显式的或继承的构造函数
-- no private or protected non-static data members - 没有私有或受保护的非静态数据成员
-- no virtual functions, and no virtual, private, or protected base classes - 没有虚函数,也没有虚拟,私有或受保护的基类
Having a deleted constructor does not count towards providing a constructor. 删除构造函数不计入提供构造函数。
Elements of an aggregate is defined as 聚合的元素定义为
The elements of an aggregate are: 聚合的元素是:
-- for an array, the array elements in increasing subscript order, or - 对于数组,数组元素按下标顺序递增,或者
-- for a class, the direct base classes in declaration order, followed by the direct non-static data members that are not members of an anonymous union, in declaration order. - 对于类,声明顺序中的直接基类,后跟声明顺序中不是匿名联合的成员的直接非静态数据成员。
Aggregate-initialization is defined as 聚合初始化定义为
[...] the elements of the initializer list are taken as initializers for the elements of the aggregate, in order. [...]初始化列表的元素按顺序作为聚合元素的初始值设定项。
Example e{}
Following the rules above the question why Example e{}
is legal is because 遵循上述规则,为什么Example e{}
是合法的是因为
the initializer is a braced initializer list
uses list initialization
since Example is an aggregate type
uses aggregate initialization
and therefore does not invoke any constructor
When you write Example e{}
, it is not default constructed. 当您编写Example e{}
,它不是默认构造的。 It is aggregate initialized. 它是聚合初始化的。 So, yes it is perfectly fine. 所以,是的,它完全没问题。
In fact, the following compiles 实际上,以下编译
struct S
{
S() = delete;
S(const S&) = delete;
S(S&&) = delete;
S& operator=(const S&) = delete;
};
S s{}; //perfectly legal
Make sure that Example
is not an aggregate type to stop aggregate initialization and delete its constructors. 确保Example
不是聚合类型以停止聚合初始化并删除其构造函数。
This is often trivial as most classes have private or protected data members. 这通常是微不足道的,因为大多数类都有私有或受保护的数据成员。 As such, it is often forgotten that aggregate initialization exists in C++. 因此,经常忘记C ++中存在聚合初始化。
The simplest way to make a class non-aggregate would be 使类非聚合的最简单方法是
struct S
{
explicit S() = delete;
};
S s{}; //illegal, calls deleted default constructor
However, as of 2017 May 30, only gcc 6.1 and above and clang 4.0.0 will reject this, all versions of CL and icc will incorrectly accept this. 但是,截至2017年5月30日,只有gcc 6.1及以上版本和clang 4.0.0将拒绝这一点,所有版本的CL和icc都会错误地接受这一点。
This is one of the craziest corners in C++, and it was
hellish
informative to look through the standard to understand what exactly happened. 这是在C ++中最疯狂的一个角落,这是
地狱般的
信息看,通过标准来了解到底发生了什么。 There have been lots of references already written and I will not attempt to explain them. 已经写了很多参考文献 ,我不会试图解释它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.