[现代有效C++] 说:
template<class T>
void f(T t){}
int main(){
f({1,2,3});
}
编译会失败,因为当模板实例化时,必须知道 T 的类型,而这里的 {1,2,3} 是大括号的 init-list。应该像这样修复:
auto x={1,2,3};//auto deduces x to std::initializer_list
f(x);
我可以理解这一点,但是我的问题:
为什么书中一直说,当用"auto"进行返值扣除时,它不能接受和推导大括号的初始化列表?
auto f()
{
return {1,2,3};
}
编译失败。
Emmmmm,如果这是 C++14 标准的一部分,我不明白为什么会有这样的限制?它继续说:
auto resetV=[&v](const auto& newValue){v=new Value;}
"newValue"前面的"auto"也不能接受{1,2,3}。为什么我们有这样的 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};
也是如此,但这被贬低了)。
为什么书中一直说,当用"auto"进行返值扣除时,它不能接受和推导大括号的初始化列表?
并不是说它"无法推断"。只是不允许。仔细考虑以下代码:
#include <initializer_list>
auto f() -> std::initializer_list<int>
{
return {1,2,3};
}
它编译吗?是的。安全吗?不。这可能会在底层阵列的生存期内引入各种问题。 std::initializer_list
不应像容器一样使用。