std::initializer_list<int>({1,2,3})和{1,2,3}有什么区别?

5

I have following template function:

template<typename T> void foo2(T t) {}

我知道不能使用以下方式调用它:

foo2({1,2,3});

因为初始化列表是模板参数的一个非推导上下文。我必须使用:

foo2<std::initializer_list<int>>({1,2,3});

但我也可以使用:
foo2(std::initializer_list<int>({1,2,3}));

让我想知道"{1,2,3}"和"std::initializer_list<int>({1,2,3})"有什么区别?

10
std::initializer_list<int>({1,2,3})是类型为std::initializer_list<int>的表达式。{1,2,3}不是一个表达式。花括号只能出现在语言规范明确允许的上下文中,而不仅仅是在任何表达式可以出现的地方。 - M.M
2
@M.M 当你知道一个没有答案的问题的答案,但是后来发现它已经在评论中被回答了。﴾ ͡° ʖ̯ ͡°﴿ - luk32
2
@luk32 随意写一个答案...我认为一个完整的答案应该涵盖模板的细节,而我对此并不确定。 - M.M
为什么自动类型推导和模板类型推导对于大括号初始化列表不同? - NathanOliver
1个回答

8
一个 花括号初始化列表(braced-init list) 不是表达式,因此没有类型。当你调用时,
foo2({1,2,3});

编译器不知道你心中的{1,2,3}代表什么类型,因此无法进行编译。

foo2<std::initializer_list<int>>({1,2,3});

这段代码可以编译,因为编译器不需要推断类型,你已经指定了类型是std::initializer_list<int>。所以它可以使用{1,2,3}初始化t

第三个调用也可以编译,因为编译器可以推断类型。std::initializer_list<int>({1,2,3})显然是一个std::initializer_list<int>,因此它可以使用传递的prvalue初始化t


2
请注意,在C++17中,“保证省略”规则使您最后一段与众不同。从某种意义上说,这里不再创建一个值,然后将其省略到函数参数中;它只是成为初始化函数参数的一种方式。或者这就是我的理解,但我还没有掌握这些新规则。(在实践中,这种情况下几乎没有任何区别) - Yakk - Adam Nevraumont

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