return和auto deduce std :: initializer_list

时间:2013-06-29 20:02:50

标签: c++ c++11

以下内容:

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的类型?

2 个答案:

答案 0 :(得分:7)

好吧,因为标准是这样说的,并且因为 braced-init-list 不是表达式。根据C ++ 11标准的5.1.2 / 4段:

  

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

     

- 如果复合语句的格式为

     

{ attribute-specifier-seq(opt) return 表达式 ; }

     lvalue-to-rvalue转换(4.1),数组到指针转换后

返回表达式的类型   (4.2),和函数到指针的转换(4.3);

     

- 否则,void

以上清楚地表明,当且仅当void语句后跟表达式时,返回类型将被推导为return以外的任何其他内容,并且 braced-init-list 本身并不是一个表达式 - 它没有类型,也没有产生值。它只是一种可以在初始化环境中使用的语言结构。

以上段落也提供了一个例子:

  

[示例

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)
     

- 结束示例]

最后,如果问题是:

为什么要引入特殊规则来推断从braced-init-list初始化的auto变量的类型,而类似的规则是引入用于推导当return后跟一个braced-init-list时,lambda的返回类型?

然后问题不具有建设性。另请注意,模板的类型推导不适用于 braced-init-lists

template<typename T>
void foo(T);

foo({1, 2}); // ERROR! T is NOT deduced to be std::initializer_list<int>

答案 1 :(得分:1)

我认为接受的答案非常有道理,但我想添加一些来自 "Effective Modern C++" by Scott Meyers 的上下文:

<块引用>

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

[...]

auto 的推导类型与模板推导类型相同,只有一个例外。

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

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