10

在下面的:

auto x = {0}; // auto deduction of std::initializer_list<int>
auto y = []() -> std::initializer_list<int> { return {0}; }(); //explicit
auto z = []() { return {0}; }(); // won't compile

为什么不能返回并自动推断 std::initializer_list 的类型?

4

2 回答 2

10

好吧,因为标准是这样说的,并且因为花括号初始化列表不是表达式。根据 C++11 标准的第 5.1.2/4 段:

[...] 如果lambda 表达式不包含trailing-return-type,就好像trailing-return-type表示以下类型:

— 如果复合语句的形式为

{ 属性说明符序列(选择) return 表达式 ; }

左值到右值转换(4.1)、数组到指针转换(4.2)和函数到指针转换(4.3)后返回表达式的类型;

——否则,void

上面清楚地表明,void当且仅当return语句后跟一个表达式时,返回类型将被推断为其他任何内容,并且花括号初始化列表本身不是表达式 - 它没有类型,它不产生价值。它只是一种可以在初始化上下文中使用的语言结构。

上一段还提供了一个例子:

[示例

auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a
                                  // braced-init-list is not an expression)

—<em>结束示例]

最后,如果问题是:

为什么引入了一个特殊的规则来推导auto从花括号初始化列表初始化的变量的类型,而没有引入类似的规则来推导 lambdareturn后跟一个花括号初始化列表的返回类型?

那么这个问题就没有建设性了。另请注意,模板的类型推导也不适用于花括号初始化列表

template<typename T>
void foo(T);

foo({1, 2}); // ERROR! T is NOT deduced to be std::initializer_list<int>
于 2013-06-29T20:06:57.650 回答
1

我认为接受的答案非常有意义,但我想从Scott Meyers 的“Effective Modern C++”中添加一些上下文:

C++98/03 有一组类型推导规则:用于函数模板的规则。C++11 稍微修改了该规则集并添加了两个,一个 forauto和一个 for decltype。然后,C++14 扩展了可以使用auto和的使用上下文decltype

[...]

auto除了一个例外,为模板推导类型与为模板推导类型相同。

  • auto类型推导通常与模板类型推导相同,但auto类型推导假定花括号初始化器表示 astd::initializer_list而模板类型推导不。
  • auto在函数返回类型或 lambda 参数中暗示模板类型推导,而不是auto类型推导。

你可能想知道为什么auto类型推导对花括号初始化器有一个特殊的规则,而模板类型推导却没有。我自己也想知道这一点。唉,我一直找不到令人信服的解释。但规则就是规则[...]。

于 2020-12-30T14:01:06.067 回答