支撑初始化列表中的对象创建顺序

sli*_*ser 15 c++ visual-studio c++11 visual-studio-2013

#include <iostream>

struct A
{
    A() { std::cout << "(A::A)"; }
};

struct B
{
    B() { std::cout << "(B::B)"; }
};

struct C
{
    template<typename ...Args>
    C(Args && ...) {}
};

int main(int agrc, char *argv[])
{
    C {A(), B()}; // <-- prints (B::B)(A::A)
    std::cout << std::endl;
    C {(A(), B())}; // <-- prints (A::A)(B::B)
    std::cout << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

  • 为什么在第一个支撑的初始列表对象中是按从右到左的顺序创建的?
  • 为什么第二种情况下的括号会恢复此顺序?

编辑:我用msvs 2013编译了它

Lig*_*ica 21

在第二个例子中,你实际上只是初始化B(); 通过使用逗号运算符,A()首先构造并丢弃.

C {(A(), B())};
//|^^^^^^^^^^|
//      \--------> (A(), B())
//                  ^^^  ^^^
//                   |    |
//                   /    \
//            evaluated,   THEN evaluated,
//            discarded      used
Run Code Online (Sandbox Code Playgroud)

另一方面,在第一个实例中,您通过初始化列表初始化C来自两个临时值的列表,其元素也应该从左到右进行评估,但是在这方面您的编译器是错误的:

[C++11: 8.5.4/4]:内的初始列表一个的支撑-INIT列表,初始化子句,从包扩展(14.5.3)导致,包括任何,都以它们出现的顺序进行评价.也就是说,与给定初始化子句相关联的每个值计算和副作用在每个值计算和副作用之前与在初始化列表的逗号分隔列表中跟随它之后的任何初始化子句相关联.[注意:无论初始化的语义如何,此评估顺序都保持不变; 例如,当initializer-list的元素被解释为构造函数调用的参数时,它适用,即使通常对调用的参数没有排序约束. - 尾注]

我可以用GCC 4.8 *重现问题,但Clang 3.5表现正常.这个bug已经在上讨论STD-讨论之前列表,但我还没有找到一个GCC的Bugzilla ID尚未§.

C {A(), B()};
// ^^^  ^^^
//  |    \
// eval-  THEN
// uated   evaluated
//  \       /
//   \     /
//  both used
Run Code Online (Sandbox Code Playgroud)

* http://coliru.stacked-crooked.com/a/1f18e0d1f8973f3c
http://coliru.stacked-crooked.com/a/5a6e7506e9be97c3
https://groups.google.com/a/isocpp.org/forum /#!话题/ STD-讨论/ TQUnBFkUBDg
§ #51253可能有关.


Naw*_*waz 5

为什么在第一个支撑的初始列表对象中是按从右到左的顺序创建的?

不,它是从左到右.你的编译器有bug,这就是它从右到左评估的原因.已知GCC(4.8)有这个bug.你用GCC吗?

为什么第二种情况下的括号会恢复此顺序?

相同.左到右.在这种情况下,逗号运算符进入图片,从左到右评估操作数.