保证副本省略和不可移动{不可移动{}}

Cu2*_*u2S 6 c++ gcc copy-elision c++17

我发现GCC 7已经实现了保证副本省略,我在wandbox中尝试了下面的代码:

#include <iostream>

struct NonMovable
{
    NonMovable() noexcept = default;
    NonMovable(NonMovable&&) noexcept = delete;
    NonMovable& operator=(NonMovable&&) noexcept = delete;
};

NonMovable Make()
{
    return {};
}


int main()
{
    //[[maybe_unused]] const auto x = Make();
    //const auto z = NonMovable{};
    [[maybe_unused]] const auto y = NonMovable{NonMovable{}};
}
Run Code Online (Sandbox Code Playgroud)

我得到编译错误:

prog.cc: In function 'int main()':
prog.cc:20:60: error: use of deleted function 'NonMovable::NonMovable(NonMovable&&)'
     [[maybe_unused]] const auto y = NonMovable{NonMovable{}};
                                                            ^
prog.cc:6:5: note: declared here
     NonMovable(NonMovable&&) noexcept = delete;
     ^~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

根据cppreference:

在初始化中,如果初始化表达式是prvalue且源类型的cv-nonqualified版本与目标类相同,则初始化表达式用于初始化目标对象:
T x = T(T(T())); // only one call to default constructor of T, to initialize x

所以我认为应该等于const Movable y{};.怎么了?

Joh*_*itb 1

列表初始化使您无法精确控制发生的情况。基本上委员会已经猜测了程序员最有可能想做的事情并分配了相应的含义。

如果想要精确控制,请使用非列表初始化。为此,您的测试用例应该绝对有效。

如果您坚持列表初始化,那么对于聚合,我认为当前的草案措辞将做到这一点并应用保证副本“省略”,因为他们说

如果 T 是聚合类,并且初始化器列表具有类型 cv U 的单个元素,其中 U 是 T 或从 T 派生的类,则从该元素初始化对象(通过复制列表初始化的复制初始化,或通过直接初始化直接列表初始化)。

此外,您可能会在标准的未来修订版或缺陷报告解决方案中得到您想要的东西,甚至对于非聚合也是如此。我相信你的课程是一个聚合,所以它应该编译。但也许我在这里缺少一些东西。