热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

你是否应该从std::optional<T>移动,其中T有非平凡的构造函数?

如何解决《你是否应该从std::optional<T>移动,其中T有非平凡的构造函数?》经验,为你挑选了1个好方法。

我正在尝试使用clang编译WebKit,并且由于基本上是以下模式而导致编译错误:

#include 
#include 

struct X {
    X() = default;
    X(const X& other) { }
};

struct Y {
    std::optional x;;
};

int main() {
    Y foo;
    Y bar(std::move(foo));
}

因此,他们使用std::optionalT(在他们的情况下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'
      : _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::_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::_Optional_base' requested here
    class optional
          ^
test.cpp:9:8: note: in implicit move constructor for 'std::optional' 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' is implicitly deleted because variant field '_M_payload' has a
      non-trivial copy constructor
          _Stored_type _M_payload;

这是有效的C++,还是WebKit坏了并且clang正确地拒绝了这段代码?



1> Barry..:

考虑这个课程:

struct X
{
    X(int);
    X(X&&) = delete;

    // does this need to invoke the move constructor??
    X() : X(X(0)) { }
};

根据gcc,答案是否定的:这直接代表X(int).根据clang的说法,答案是肯定的,这不符合汇编:

:55:15: error: call to deleted constructor of 'X'    
        X() : X(X(0)) { }   
              ^ ~~~~    
: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{},
                      std::move(__other._M_payload))
          : _Optional_payload(__ctor_tag{}))
  { }

此类型隐式删除了复制和移动构造函数,因为与成员的联合不是简单的可复制构造.因此,如果这个委托构造函数必须调用隐式复制构造函数(如clang所认为的那样),那么这是不正确的.如果它不必,并且只调用一个或另一个委托构造函数,那么这个调用就可以了.


最近在核心反射器上讨论了这个确切的例子 - 参见标题为"强制复制省略与ctor授权"的主题.
推荐阅读
author-avatar
kmv2145234
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有