C++ 通过move from函数返回值进行大括号初始化;过剩元素“;错误

C++ 通过move from函数返回值进行大括号初始化;过剩元素“;错误,c++,c++11,c++14,move-semantics,c++17,C++,C++11,C++14,Move Semantics,C++17,给定以下代码段: class Foo {}; Foo makeFoo() { return Foo{}; } int main() { Foo myFoo{makeFoo()}; } 我希望main中的单行使用Foo的move构造函数在makeFoo()的返回值上声明和定义/初始化myFoo 但是,我从clang++3.5.1(在C++14模式下编译)中得到以下错误: 这是怎么回事?“结构初始值设定项”的确切含义是什么——它只是POD的默认(无参数)构造函数吗?为什么不调用移动构造函数?

给定以下代码段:

class Foo {};
Foo makeFoo() { return Foo{}; }

int main()
{
  Foo myFoo{makeFoo()};
}
我希望
main
中的单行使用
Foo
的move构造函数在
makeFoo()的返回值上声明和定义/初始化
myFoo

但是,我从
clang++
3.5.1(在C++14模式下编译)中得到以下错误:


这是怎么回事?“结构初始值设定项”的确切含义是什么——它只是POD的默认(无参数)构造函数吗?为什么不调用移动构造函数?

因为
Foo
是一个聚合,所以执行聚合初始化

N3797§8.5.4【dcl初始列表】/3:

类型为T的对象或引用的列表初始化定义如下:

  • 如果T是聚合,则执行聚合初始化(8.5.1)
根据N4296,对于C++17,这似乎已经改变:

类型为T的对象或引用的列表初始化定义为 如下:

  • 如果T是类类型,且初始值设定项列表具有 cv U类型的单个元素,其中U是T或从T派生的类, 从该元素初始化对象(通过复制初始化) 用于复制列表初始化,或通过直接初始化 直接列表初始化)
毕竟,没有“通用(或统一)初始化语法”这样的东西。列表初始化有一些特殊的行为

在您的情况下,相关规则见第8.5.1节:

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),也没有虚拟函数(10.3)

因此,您的
类Foo
是一个聚合

当聚合由初始值设定项列表初始化时,如8.5.4所述,初始值设定项列表中的元素被视为聚合成员的初始值设定项,下标或成员顺序递增。每个 成员是从相应的初始值设定项子句复制初始化的。如果初始值设定项子句是一个表达式,并且需要进行缩小转换(8.5.4)来转换该表达式,则程序的格式不正确

<>这是编译器如何解释您的代码(正如克里斯指出的那样),在下一个C++版本中,它不会这样做……尽管我认为这个规则也需要更新,只是“在85.4中指定的”并不足以阻止聚合初始化行为。 因为初始化者比成员多,这是非法的

类的聚合也可以使用单个表达式初始化,该表达式不包含在大括号中,如8.5所述


这是允许复制/移动初始化的规则。聚合的复制/移动不能使用大括号。

当然它可以与
foomyfoo(makeFoo())一起使用。讨厌brace init中的不一致!甚至在
Foo
中加入一个ctor也能使它工作。但我想这与“聚合初始化”有关。奇怪的是,Clang3.7同时使用
-std=c++14
-std=c++1z
编译了这两个文件,Clang3.5在这两个文件中都给出了一个错误(这是一个容易理解的地方)。@chris这很奇怪。根据下面的答案,这听起来像是一个新的bug,也许?@KyleStrand:目的似乎是在C++1z中允许这样做。然而,目前的草案有相互冲突的规则。@chris呃,没关系,这只是标准在快速波动,我猜,血腥的皮拉^W^W^W^Wbrace init!主初始化算法在8.5/17中,对于带括号的init列表跳到8.5.4,然后对于聚合跳到8.5.1。除非8.5.4真的跳到它上面,否则8.5.1所说的是无关紧要的。@T.C.:标准规则不是这样工作的。如果先决条件得到满足,则所有规则均适用,这大概就是为什么本规则在第8.5.4条中有先决条件。。。但正确的先决条件是“8.5.4调用聚合初始化”,而不是“8.5.4通过初始化器列表初始化聚合”。由于这是一个缺陷报告,编译器甚至可能在C++14模式下实现该解决方案。
error: excess elements in struct initializer
      Foo myFoo{makeFoo()};
                ^~~~~~~~~
1 error generated.