考虑以下示例以了解initializer-list-constructor的用法:

std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" });
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" };

两者之间是否有任何差异(甚至略有差异)?

在一个大的项目,在那里你必须定义一个标准,你会选择哪一种风格?
我更喜欢第一种样式,第三种样式很容易与带有args的构造函数的调用混淆。同样,第一种样式看起来对其他编程语言也很熟悉。

最佳答案

如果vectorstring,则这三种形式之间没有区别。但是,如果采用initializer_list的构造函数为explicit,则前两者之间可能会有所不同。在这种情况下,不允许使用第一个(即复制列表初始化),而允许使用其他两个(即直接列表初始化)。

因此,我更喜欢第三种形式。我会避免第二个,因为括号是多余的。

正如Yakk在注释中指出的那样,当正在构造的类型没有采用initializer_list的构造函数时,还会出现进一步的差异。

例如,正在构造的类型具有一个构造函数,该构造函数带有3个参数(均为char const *类型),而不是initializer_list构造函数。在这种情况下,格式1和3有效,但格式2格式不正确,因为当放在括号中时,braced-init-list无法匹配3参数构造函数。

如果该类型确实具有初始化程序列表构造函数,但braced-init-list的元素不能隐式转换为initializer_list<T>,则将考虑其他构造函数。假设存在另一个匹配项的构造函数,则形式2会导致构造中间拷贝,而其他两个不会。这可以用-fno-elide-constructors编译的following example证明。

struct foo
{
    foo(int, int) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    foo(foo const&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    foo(std::initializer_list<std::string>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

int main()
{
    foo f1 = {1,2};
    std::cout << "----\n";
    foo f2({1,2});
    std::cout << "----\n";
    foo f3{1,2};
}

输出:
foo::foo(int, int)
----
foo::foo(int, int)
foo::foo(const foo&)
----
foo::foo(int, int)



以下情况不是问题的一部分,但仍然值得注意。在某些情况下,使用嵌套括号可能会导致不直观的行为。考虑
std::vector<std::string> v1{{ "xyzzy", "plugh", "abracadabra" }};
std::vector<std::string> v2{{ "xyzzy", "plugh"}};
v1可以正常工作,将是一个包含3个字符串的vector,而v2会导致未定义的行为。有关详细说明,请引用this answer

关于c++ - 调用Initializer-List-Constructor的不同方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25120659/

10-10 17:28