Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用初始值设定项列表构造函数的不同方法_C++_C++11_Initialization List - Fatal编程技术网

C++ 调用初始值设定项列表构造函数的不同方法

C++ 调用初始值设定项列表构造函数的不同方法,c++,c++11,initialization-list,C++,C++11,Initialization List,考虑以下初始化器列表构造函数用法示例: std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" }; std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" }); std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; std::vector v={“

考虑以下初始化器列表构造函数用法示例:

std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" });
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; 
std::vector v={“xyzy”、“plugh”、“abracadabra”};
向量v({“xyzy”,“plugh”,“abracadabra”});
向量v{“xyzy”,“plugh”,“abracadabra”};
他们之间有什么区别(甚至是细微的区别)

在需要定义标准的大型项目中,您会选择哪种样式?

我更喜欢第一种样式,第三种样式很容易与使用args调用构造函数混淆。另外,第一种样式看起来也为其他编程语言所熟悉。

对于
字符串的
向量
,这三种形式之间没有区别。但是,如果使用
初始值设定项列表的构造函数是
显式的
,则第一个和其他两个构造函数之间可能存在差异。在这种情况下,不允许进行第一次复制列表初始化,而允许进行其他两次直接列表初始化

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


正如雅克在评论中指出的那样,当所构造的类型没有采用
初始值设定项列表的构造函数时,会出现进一步的差异

比如说,正在构造的类型有一个构造函数,它接受3个参数,所有类型都是
char const*
,而不是
初始值设定项\u list
构造函数。在这种情况下,表单1和3是有效的,但表单2的格式不正确,因为括号中的init列表无法与3参数构造函数匹配

如果类型确实具有初始值设定项列表构造函数,但带括号的init list的元素不能隐式转换为
初始值设定项列表
,则将考虑其他构造函数。假设存在另一个匹配的构造函数,则表单2会生成一个正在构造的中间副本,而其他两个则不会。这可以通过使用
-fno-elide构造函数编译的来演示

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};
}


下面的案例不是问题的一部分,但仍然值得注意。在某些情况下,使用嵌套大括号可能会导致不直观的行为。考虑

std::vector<std::string> v1{{ "xyzzy", "plugh", "abracadabra" }};
std::vector<std::string> v2{{ "xyzzy", "plugh"}};
向量v1{{“xyzy”,“plugh”,“abracadabra”}; std::向量v2{{“xyzy”,“plugh”};

v1
按预期工作,将是一个包含3个字符串的
向量,而
v2
会导致未定义的行为。有关详细说明,请参阅。

这是一个很好的问题,尽管主要是基于意见。我投票支持(1),因为它强调使用
std::initializer\u list
。我投票支持#3,从#1开始,人们可能会误以为运算符=和复制构造函数是used@exceptyon在初始化时,你认为<代码> =/COD> > Madis<代码>运算符=/COD>你需要把一个AN变成C++类。编码标准不应旨在确保非程序员能够理解代码。Yakk你应该始终像在你之后的人一样编程。第二种形式让我在隐式/显式的基础上吐出一点东西,当所构造的对象没有初始值设定项列表构造函数时,其他两种形式不同,如果传递的类型没有转换为对象具有的列表构造函数的类型。检查
std::vector({1,3})
vs
{1,3}
@Yakk很好,我更新了关于第一部分的答案。我理解你在第二部分中所说的,关于缺少隐式转换,但是你评论中的这些片段都不会编译,我很难给出一个例子来说明这两种形式做不同的事情。但是它们不会编译,原因不同!如果列表失败,
T{a,b}
将尝试为
T
找到一个2-arg构造函数,而
T({1,3})
将尝试用
{1,3}
构造一个
T
的1-arg构造函数参数(包括复制构造函数,如果它存在的话)<代码>结构foo{foo(int,int);foo(foo const&)=delete;}@Yakk啊好的,现在我明白你的意思了。是的,他们失败的方式不同,原因正如你所描述的。后一种情况考虑复制cTor。我将在一段时间内更新答案。@很公平,我已经非常清楚地表明,嵌套大括号不是原始问题的一部分。我觉得它与当前的主题有足够的相关性,因为您正在询问初始化中大括号和圆括号的不同组合的细微差别。如果是
map
,则需要嵌套的大括号,因为其
初始值设定项列表
构造函数采用
std::vector<std::string> v1{{ "xyzzy", "plugh", "abracadabra" }};
std::vector<std::string> v2{{ "xyzzy", "plugh"}};