Nik*_* B. 11 c++ webkit optional c++17
我正在尝试使用clang编译WebKit,并且由于基本上是以下模式而导致编译错误:
#include <iostream>
#include <optional>
struct X {
X() = default;
X(const X& other) { }
};
struct Y {
std::optional<X> x;;
};
int main() {
Y foo;
Y bar(std::move(foo));
}
Run Code Online (Sandbox Code Playgroud)
因此,他们使用std::optional<T>T(在他们的情况下WTF::Variant)具有非平凡的复制/移动构造函数,然后使用std::optional移动构造函数.这适用于GCC 8.1.1,但不适用于clang 6.0.1(使用GCC 8.1.1的libstdc ++):
In file included from test.cpp:2:
/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.1/../../../../include/c++/8.1.1/optional:276:9: error: call to implicitly-deleted copy constructor of 'std::_Optional_payload<X, true, true, true>'
: _Optional_payload(__engaged
^ ~~~~~~~~~
/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.1/../../../../include/c++/8.1.1/optional:739:4: note: in instantiation of member function 'std::_Optional_payload<X, true, true, true>::_Optional_payload' requested here
: _M_payload(__other._M_payload._M_engaged,
^
/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.1/../../../../include/c++/8.1.1/optional:985:11: note: in instantiation of member function 'std::_Optional_base<X, false, false>::_Optional_base' requested here
class optional
^
test.cpp:9:8: note: in implicit move constructor for 'std::optional<X>' first required here
struct Y {
^
test.cpp:15:7: note: in implicit move constructor for 'Y' first required here
Y bar(std::move(foo));
^
/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.1/../../../../include/c++/8.1.1/optional:288:24: note: copy constructor of '_Optional_payload<X, true, true, true>' is implicitly deleted because variant field '_M_payload' has a
non-trivial copy constructor
_Stored_type _M_payload;
Run Code Online (Sandbox Code Playgroud)
这是有效的C++,还是WebKit坏了并且clang正确地拒绝了这段代码?
考虑这个课程:
struct X
{
X(int);
X(X&&) = delete;
// does this need to invoke the move constructor??
X() : X(X(0)) { }
};
Run Code Online (Sandbox Code Playgroud)
根据gcc,答案是否定的:这直接代表X(int).根据clang的说法,答案是肯定的,这不符合汇编:
Run Code Online (Sandbox Code Playgroud)<source>:55:15: error: call to deleted constructor of 'X' X() : X(X(0)) { } ^ ~~~~ <source>:52:9: note: 'X' has been explicitly marked deleted here X(X&&) = delete; ^
这似乎是核心语言问题的可能性,因为一方面[class.base.init]/6说:
目标构造函数由重载决策选择.目标构造函数返回后,将执行委托构造函数的主体.
也就是说,我们专门讨论选择一个构造函数并调用它 - X(X&&)在这种情况下肯定会这样.但另一方面,下一段说明这是初始化:
的表达式列表或支撑-INIT列表在MEM-初始化是根据[dcl.init]用于初始化规则用来初始化指定子对象(或者,在一个委派构造,完整的类对象的情况下)直接初始化.
这看起来很像[dcl.init] /17.6中的保证副本省略示例:
如果初始化表达式是prvalue且源类型的cv-nonqualified版本与目标类相同,则初始化表达式用于初始化目标对象.[示例:
T x = T(T(T()));调用T默认构造函数进行初始化x. - 结束例子]
我不确定哪种解释是正确的,但铿锵拒绝对我来说似乎并不明显.
为什么这个例子相关?optional在libstdc ++中的移动构造函数,对于那些可以轻易破坏的类型,可以轻易地复制/移动可分配(比如你的X)经历:这个构造函数:
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{ }
Run Code Online (Sandbox Code Playgroud)
此类型隐式删除了复制和移动构造函数,因为与成员的联合不是简单的可复制构造.因此,如果这个委托构造函数必须调用隐式复制构造函数(如clang所认为的那样),那么这是不正确的.如果它不必,并且只调用一个或另一个委托构造函数,那么这个调用就可以了.