【发布时间】:2019-12-24 16:33:11
【问题描述】:
我正在尝试使用auto 自动推断嵌套std::initializer_list 的类型。
auto list = {
{{ 0, 1}, { 2, 3 }},
{{ 4, 5}, { 6, 7 }},
};
这里的实际类型是std::initializer_list<std::initializer_list<std::initializer_list<int>>>,但是当我尝试编译它时,我收到一个错误,指出auto 无法推断出类型。有没有办法让auto 识别这样的构造?
我有一个程序,其中这些初始化列表可以是任意大小和深度,因此硬编码类型是不切实际的。
附加信息:
我在这里找到了关于初始化列表的文档:https://en.cppreference.com/w/cpp/language/list_initialization
braced-init-list 不是表达式,因此没有类型,例如
decltype({1,2})格式不正确。没有类型意味着模板类型推导不能推导出与花括号初始化列表匹配的类型,因此给定声明template<class T> void f(T);表达式f({1,2,3})是格式错误的。但是,模板形参也可以推导出来,就像std::vector<int> v(std::istream_iterator<int>(std::cin), {})的情况一样,其中迭代器类型由第一个参数推导,但也用于第二个参数位置。使用关键字 auto 进行类型推导有一个特殊例外,它在复制列表初始化中将任何花括号初始化列表推导出为std::initializer_list。
文档似乎表明使用auto 进行类型推导有一个特殊例外,因此您会认为这会起作用...但似乎当您使用嵌套列表时auto 无法推断类型.
【问题讨论】:
-
如果你知道类型,就声明它。使用
auto似乎很懒惰,就像在允许var关键字的语言中使用的糟糕的编程策略一样。 C++ 是一种类型化语言,这意味着每个变量都有一个一旦声明就不能改变的类型。除非您的代码文件可以包含多少个字符,否则您只需声明类型并完成它。 -
@JoelTrauger 阅读了问题的最后一句话。大小/深度可以变化。无法在任何地方硬编码类型,因为类型并不总是相同。
-
我不完全确定,但我认为即使您手动指定类型,您也会得到一个“悬空”初始化列表。见stackoverflow.com/questions/59136795/… 和en.cppreference.com/w/cpp/utility/initializer_list
-
@JoelTrauger 我不是在寻找运行时灵活性,这是编译时灵活性。
auto在编译时推断类型,而不是运行时。 -
@JoelTrauger 这既不是“穷”也不是“懒惰的编程策略”。它按预期使用强类型——作为程序员的福音,而不是语法障碍。查看具有高级类型系统的语言,例如 Haskell 和 Ocaml,了解它们如何处理这个问题。
标签: c++ initializer-list auto type-deduction