是否可以初始化不可复制类型的成员变量(或基类)
Is it possible to initialize member variable (or base class) of a non-copyable type?
考虑以下代码:
struct S
{
S() = default;
S(S const&) = delete;
// S(S&&) = delete; // <--- uncomment for a mind-blowing effect:
// MSVC starts compiling EVERY case O_O
};
S foo() { return {}; }
struct X : S
{
// X() : S(foo()) {} // <----- all compilers fail here
};
struct Y
{
S s;
Y() : s(foo()) {} // <----- only MSVC fails here
};
struct Z
{
S s = {}; // ... and yet this is fine with every compiler
Z() {}
};
//S s1(foo()); // <-- only MSVC fails here
//S s2 = foo(); // <-- only MSVC fails here
问题:
看起来没有办法用prvalue初始化不可复制的基类——这是正确的吗?看起来标准中有缺陷(或者我尝试的所有编译器都不兼容(
MSVC无法初始化成员变量——这是否意味着它不符合要求?有办法解决这个问题吗?
为什么添加
S(S&&) = delete;
会导致MSVC在每个情况下编译?
因此,我认为我找到了标准的相关部分,并且我认为编译器在X
方面存在错误。(所有链接都指向一个标准草案,所以在C++17中可能会有所不同,我稍后会检查。但gcc10和clang10在-std=c++20
中也会失败,所以这并不重要(。
关于基类的初始化(emphasis mine(:class.base.init/7
mem初始化器中的表达式列表或braked init列表用于根据[dcl.init]的初始化规则初始化指定的子对象(或者,在委托构造函数的情况下,是完整的类对象(,以进行直接初始化。
我认为这告诉我们,X() : S(foo()) {}
应该与S s = foo()
没有什么不同,但让我们看看dcl.init/17.6.1
如果初始值设定项表达式是一个prvalue,并且源类型的cv不合格版本与目标的类是同一类,则初始值设定值表达式用于初始化目标对象。[示例:
T x = T(T(T()));
调用T
默认构造函数初始化x
。--结束示例]
这意味着X() : S(foo()) {}
应该调用默认构造函数。我还测试了(与示例完全一致(X() : S(S()) {}
,这在clang和g++上也失败了。所以在我看来,编译器有一个缺陷。
看起来没有办法用prvalue初始化不可复制的基类——这是正确的吗?看起来标准中有缺陷(或者我尝试的所有编译器都不兼容(
标准说它应该有效。这个标准是错误的。
基类子对象(更常见的是,潜在重叠的子对象(可能具有与相同类型的完整对象不同的布局,或者其填充可以被其他对象重用。因此,不可能从返回prvalue的函数中删除副本或移动,因为该函数不知道它没有初始化一个完整的对象。
剩下的都是微软风投的bug。
不,这是不允许的,但自从c++17
以来,有了一些新功能,其中一个功能不再是copy object
。
函数返回prvalues不再复制对象(
mandatory copy elision
(,并且有一个新的prvalue到glvalue的转换称为临时物化转换。此更改意味着复制省略现在有保证,并且甚至适用于不可复制或可移动的类型。这允许您定义返回这样的类型。
有保证的拷贝省略C++17
下面的函数,从不返回S()
对象并返回std::initialization_list
或{}
,而是作为S s ={}
,是一个有效的转换,因此基于副本省略优化的不是要返回副本,粗略地说-直接返回std::initialization_list
本身。注意临时物化转换。
S foo() { return {}; }
以下不起作用,
S foo() { S s = {}; return s; }
因此,行Y() : s(foo()) {}
,粗略地说-现在可以被解释为隐式类型转换,
S s = {}
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- C++预处理会生成变量成员、资源库和映射
- 局部堆栈变量成员的返回值优化
- Google Mock:在目标类的构造函数中实例化的模拟私有变量成员
- 使用指向结构变量成员的指针访问该结构的成员的地址
- 如果派生类仅包含自动变量成员,是否有必要具有虚拟驱动器
- 线程安全性和静态变量/成员功能
- "static const char array"可以在 C 语言上包含变量成员吗
- 仅用于内部目的的类的所有变量/成员的技术术语是什么
- 如何强制转换变量成员以将其作为函数的引用参数传递
- 类中未声明变量成员函数
- 在 main 中初始化类的 "static const" 类型变量成员的更好方法
- c++模板类静态const变量成员作为映射键给出未定义引用
- 在类中初始化结构变量成员会导致分割错误
- 在c++中建模变量成员类型
- 模板私有静态变量成员的未定义符号
- 不能访问公共静态变量成员
- 常量变量成员在C++有什么用?
- g++ 4.8.2坚持简单变量成员是数组