已删除默认构造函数。仍然可以创建对象。。。有时 天真,乐观,还有。。所以对c++11统一初始化语法的看法是错误的
我认为,由于C++11用户定义的类型对象应该使用新的已删除默认构造函数。仍然可以创建对象。。。有时 天真,乐观,还有。。所以对c++11统一初始化语法的看法是错误的,c++,c++14,language-lawyer,list-initialization,aggregate-initialization,C++,C++14,Language Lawyer,List Initialization,Aggregate Initialization,我认为,由于C++11用户定义的类型对象应该使用新的{…}语法而不是旧的(…)语法来构造(除了std::initializer\u list的构造函数重载和类似的参数(例如std::vector:size-ctor vs-elem-init\u-list-ctor)) 好处是:没有狭窄的隐式转换,没有最麻烦的解析问题,一致性(?)。我认为没有问题,因为我认为它们是一样的(除了给出的例子) 但事实并非如此 纯粹疯狂的故事 {}调用默认构造函数 。。。除非: 默认构造函数将被删除并删除 没有定义其
{…}
语法而不是旧的(…)
语法来构造(除了std::initializer\u list
的构造函数重载和类似的参数(例如std::vector
:size-ctor vs-elem-init\u-list-ctor))
好处是:没有狭窄的隐式转换,没有最麻烦的解析问题,一致性(?)。我认为没有问题,因为我认为它们是一样的(除了给出的例子)
但事实并非如此
纯粹疯狂的故事
{}
调用默认构造函数
。。。除非:
- 默认构造函数将被删除并删除
- 没有定义其他构造函数
{}
也可以创建对象。这不正是删除构造函数的全部目的吗
…除非:
- 该对象具有已删除的默认构造函数和
- 定义的其他构造函数
- 该对象具有已删除的构造函数和
- 没有定义其他构造函数,并且
- 至少有一个非静态数据成员
{value}
来构造对象
好的,也许这与第一个异常相同(对象的值init)
…除非:
- 该类具有已删除的构造函数
- 以及初始化类default中的至少一个数据成员
{}
或{value}
都不能创建对象
我肯定我错过了一些。讽刺的是,它被称为统一初始化语法。我再说一遍:UNIFORM初始化语法
这是什么疯狂
情景A
已删除默认构造函数:
情景B
已删除默认构造函数,其他构造函数已删除
情景C
已删除默认构造函数,已定义其他构造函数
情景D
已删除默认构造函数,未定义其他构造函数,数据成员
情景E
已删除默认构造函数、已删除T构造函数、T数据成员
情景F
已删除默认构造函数、类内数据成员初始值设定项
当以这种方式看待事物时,很容易说在初始化对象的方式中存在着完全和彻底的混乱 最大的区别来自
foo
的类型:它是否是聚合类型
如果有以下情况,则为聚合:
- 没有用户提供的构造函数(已删除或默认的函数不算作用户提供的)
- 没有私有或受保护的非静态数据成员
- 非静态数据成员没有大括号或相等的初始值设定项(从c++11到(在c++14中恢复)
- 没有基类
- 没有虚拟成员函数
- 在场景A B D E:
是一个聚合foo
- 在场景C中:
不是聚合foo
- 情景F:
- 在c++11中,它不是聚合
- 在c++14中,它是一个聚合
- g++没有实现这一点,即使在C++14中,它仍然将其视为非聚合。
没有实现这一点4.9
5.2.0
没有(可能是回归)5.2.1 ubuntu
- 如果T是聚合类型,则执行聚合初始化。这将考虑场景A B D E(和C++14中的F)
- 否则,T的施工人员将分两个阶段考虑:
- 接受std::initializer\u列表的所有构造函数
- 否则[…]T的所有构造函数都参与重载解析[…]这将处理C(以及C++11中的F)
- 每个非静态类成员在类定义中的顺序外观都是从 初始化列表。(省略数组引用)
TL;DR 所有这些规则看起来仍然非常复杂,令人头痛。我个人对此过于简化(如果我因此射中了自己的脚,那就这样吧:我想我会在医院里呆两天,而不是头痛几十天):
- 对于聚合,从列表初始值设定项的元素初始化每个数据成员
- else调用构造函数
这不正是删除构造函数的全部目的吗 我不知道,但解决办法是让
foo
不是一个聚合。不增加开销且不改变对象所用语法的最常见形式是使其从空结构继承:
struct dummy_t {};
struct foo : dummy_t {
foo() = delete;
};
foo f{}; // ERROR call to deleted constructor
在某些情况下(我想根本没有非静态成员),替代方法是删除析构函数(这将使对象在任何上下文中都不可实例化):
此答案使用从以下方面收集的信息:
struct foo {
foo() = delete;
foo(int) = delete;
};
foo f{}; // OK
struct foo {
foo() = delete;
foo(int) {};
};
foo f{}; // error call to deleted constructor
struct foo {
int a;
foo() = delete;
};
foo f{}; // error use of deleted function foo::foo()
foo f{3}; // OK
struct foo {
int a;
foo() = delete;
foo(int) = delete;
};
foo f{}; // ERROR: missing initializer
foo f{3}; // OK
struct foo {
int a = 3;
foo() = delete;
};
/* Fa */ foo f{}; // ERROR: use of deleted function `foo::foo()`
/* Fb */ foo f{3}; // ERROR: no matching function to call `foo::foo(init list)`
struct dummy_t {};
struct foo : dummy_t {
foo() = delete;
};
foo f{}; // ERROR call to deleted constructor
struct foo {
~foo() = delete;
};
foo f{}; // ERROR use of deleted function `foo::~foo()`
struct X {
X() = delete;
};
int main() {
X x1; // ill-formed - default c’tor is deleted
X x2{}; // compiles!
}
struct X {
private:
X() = default;
};
int main() {
X x1; // ill-formed - default c’tor is private
X x2{}; // compiles!
}
static_assert(!std::is_default_constructible_v<X>);