统一初始化语法差异

10

做什么的区别是什么?

A a{ A() };

还有,

A a( A{} );

如何避免最具烦恼的解析?什么时候应该使用特定的方法?


2
在这种特定情况下,最简单的选项是 A a;,对吗?如果我没有误解,你建议的语法只有在你想传递给 A 构造函数的临时对象类型与 A 不同时才有意义,对吗?也就是说,A a { B() }; - jogojapan
2个回答

13

这两种语法在大多数情况下是等价的,选择哪种语法主要取决于个人口味。如果您喜欢统一初始化,我建议使用以下方式:

A a{ A{} };

否则,可以仅使用括号来消除歧义:
A a((A())); // This can't be parsed as a function declaration

请注意,有一种情况(非常不可能,我必须说)在这种情况下你问题中显示的这两种形式并不等价。如果你的类 A 有一个接受 initializer_list<A> 的构造函数,那么当使用大括号时,该构造函数将优先于复制构造函数:

#include <initializer_list>
#include <iostream>

struct A
{
    A() { }
    A(std::initializer_list<A> l) { std::cout << "init-list" << std::endl; }
    A(A const& a) { std::cout << "copy-ctor" << std::endl; }
};

int main()
{
    A a(A{}); // Prints "copy-ctor" (or nothing, if copy elision is performed)
    A b{A()}; // Prints "init-list"
}

上述差异在这个实时示例中展示。

2
实际上,第一个对我没有打印“copy-ctor”。我认为这是复制省略。 - Me myself and I
@MemyselfandI:嗯,对的,编译器正在省略复制 - 但从概念上讲,复制构造函数被选中。 - Andy Prowl
1
@MemyselfandI:不,在许多编译器上,它将始终启用,除非您明确禁用它。 - Mankarse
@MemyselfandI: 不一定。复制省略是完全由编译器决定的,但在启用优化时发生的可能性更大。 - Andy Prowl
2
请注意,在clang上,-fno-elide-constructors目前存在问题(http://llvm.org/bugs/show_bug.cgi?id=12208)。 - Mankarse
显示剩余2条评论

9
在大多数情况下,它们是等效的,但是A a{ A() };将优先使用std::initializer_list构造函数(如果存在),而A a( A{} );将首选移动/复制构造函数。
当构造调用移动/复制构造函数时,新对象的构造可以被省略,但这对于std::initializer_list构造函数不可能。
两种语法都不会被解析为函数声明,因此两者都避免了最令人困惑的解析。
#include <iostream>
#include <initializer_list>
struct A {
    A() {
        std::cout << "A()\n";
    }
    A(A&&) {
        std::cout << "A(A&&)\n";
    }
    A(std::initializer_list<A>) {
        std::cout << "A(std::initializer_list<A>)\n";
    }
};
int main()
{
    {A a{ A() };} // Prints "A()\n" "A(std::initializer_list<A>)\n"
    {A a( A{} );} // Prints "A()\n" and *possibly*
                  // (depending on copy elision) "A(A&&)\n"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接