我发现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{}};
}
我收到了编译错误:
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;
^~~~~~~~~~
根据cppreference:
在初始化中,如果初始化表达式是prvalue而且 cv-源类型的非限定版本与该类相同 目的地的类,初始化表达式用于 初始化目标对象:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
所以我认为它应该等于const Movable y{};
。怎么了?
答案 0 :(得分:1)
列表初始化使您无法精确控制发生的情况。基本上,委员会已经猜到了程序员可能最想做的事情,并分配了相应的含义。
如果要进行精确控制,请使用非列表初始化。为此,您的测试用例应该可以正常工作。
如果你坚持列表初始化,那么对于聚合,我认为目前的草案措辞会做到并应用保证副本“elision”,因为他们说
如果T是聚合类,并且初始化列表具有cv U类型的单个元素,其中U是T或从T派生的类,则从该元素初始化对象(通过复制 - 初始化复制列表 - 初始化,或直接初始化直接列表初始化)。
此外,您可能在未来的标准版本或缺陷报告解决方案中获得您想要的内容,即使对于非聚合也是如此。我相信你的类是一个聚合,所以它应该编译。但也许我在这里缺少一些东西。