[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}。为什么我们有这两个限制?
我想也许从语言设计的角度来看,在进行类型演绎时会有一些混淆?只是一个猜测。 这些设计决策的任何线索?它困扰了我好几天。
感谢。
答案 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
不应该像容器一样使用。