为什么“auto”在推导返回值时无法接受braced-init-list?

时间:2016-06-09 05:06:53

标签: c++ list initialization c++14 auto

[Modern Effective C ++]说:

template<class T>
void f(T t){}
int main(){
    f({1,2,3});
}

编译失败,因为在模板实例化时,必须知道T的类型,而这里{1,2,3}是braced-init-list。应修好如:

auto x={1,2,3};//auto deduces x to std::initializer_list
f(x);

我能理解这一点,但接下来是我的问题:

为什么本书继续说,当使用“auto”进行返还值扣除时,它不能接受和推断braced-init-list?

auto f()
{
    return {1,2,3};
}

编译失败。

嗯,如果这是C ++ 14标准的一部分,我不明白为什么会有这样的限制?它继续说:

auto resetV=[&v](const auto& newValue){v=new Value;}

“newValue”之前的“auto”也不能接受{1,2,3}。为什么我们有这两个限制?

我想也许从语言设计的角度来看,在进行类型演绎时会有一些混淆?只是一个猜测。 这些设计决策的任何线索?它困扰了我好几天。

感谢。

2 个答案:

答案 0 :(得分:2)

std::initializer_list是对匿名数组的引用。

数组本身位于创建initializer_list的块范围内。

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

几乎完全没用,因为数组的生命周期是f的主体,而引用它的initializer_list存在于几乎完全不相交的代码段中。

使用initializer_list几乎可以肯定是未定义的行为。您可能会询问它的大小以及它是否为空,这可能是已定义的行为(不知道,不用太在意检查),但您绝对无法检查其内容。

初始化列表是对数据的引用,而不是数据的副本。

如果:

auto f() {
  return {1,2,3};
}

推断自己是上面的,它几乎从来没用过。

auto x = {1,2,3};有效的例外情况是唯一一种initailizer_list<int>可以从{}推导出来的情况。 (在C ++ 11中,auto x{1};也是如此,但这已经被删除了。

答案 1 :(得分:1)

  

为什么本书继续说,当使用“auto”进行返还值扣除时,它不能接受和推断braced-init-list?

并不是说“不能推断它”。这是不允许的。仔细考虑这段代码:

#include <initializer_list>

auto f() -> std::initializer_list<int>
{
    return {1,2,3};
}

编译吗?是。安全吗?不会。这可能会在底层阵列的生命周期中引入各种问题。 std::initializer_list不应该像容器一样使用。