将'std::initializer_list<int>'转换为'int'

3

为什么我不能像使用“普通”变量一样使用使用“initializer_list”分配的变量?

代码:

void stovr(int a){}
int main() {

   auto v {5}; // v is std::initializer_list<int>
   stovr(v);  // cannot convert 'std::initializer_list<int>' to 'int'

}
  • 为什么没有隐式转换?(编辑:因为v是列表)
  • 为什么vlist而不是int

2
将代表“许多东西”的东西隐式转换为其中的一个单一物品并不太有意义,可能会导致代码错误。 - juanchopanza
5
新版本的 C++ 标准修复了一个奇怪的行为,即 auto 解析。现在使用 auto v {5}; 会将 v 声明为一个 int 类型。 - user743382
2
@Person.Junkie 是的,但允许从initializer_list<T>T的转换将是“新手”更糟糕错误的另一个来源。这就像通过砍掉头来治疗头痛一样。 - juanchopanza
2
@juanchopanza 你是正确的。这种转换是个坏主意。 但是 auto v{5} 必须是 int )) - Person.Junkie
2
@Person.Junkie 是的,那将是正确的修复方法,并且如果我没记错的话,它已经在 C++14 中实现了。 - juanchopanza
显示剩余4条评论
2个回答

7

std::initializer_list<T> 无法转换为 T 的原因与 T[]vector<T> 相同:如果你仅仅知道你有一个 std::initializer_list<T>,你不知道它有多少个元素。

std::initializer_list<int> x = { 1, 2, 3 }; 是完全有效的。如果从 std::initializer_list<int>int 存在隐式转换,你期望看到哪个值呢?


虽然这引出了一个问题:“实际上,你为什么不知道呢?”。初始化程序列表肯定知道项目数量,甚至公开了一个size成员函数。因此,合理地期望(我猜可能是?)它实现了一个带有enable_if_t(size() == 1, value_type)标记的operator T - Damon
@Damon 不,那是不可能的。size()在运行时被评估。enable_if_t需要一个可以在编译时评估的条件。如果大小是类型的一部分(std::initializer_list<int, 1>),那么这是可能的,但这会带来更多问题而不是解决问题。 - user743382
不幸的是,对size成员函数的调用不是常量表达式。真遗憾。 - Columbo
看起来 GCC 的 initializer_list 不符合标准。我在我的 4.9.2 标头文件中找到了一个带有迭代器和大小的 constexpr 构造函数,以及一个 constexpr 成员 size。尽管这显然“运行良好”,并且据我所知没有不这样做的好理由,但你可以争辩说这真正是标准的问题。 - Damon
即使标准规定它应该是“constexpr”,也无法满足您想要使用它的需求。它只能用于具体的std::initializer_list<T>实例,因此不能在实例化上下文中用作常量表达式。 - user743382

2
“一个带括号的初始化器没有类型!一个带括号的初始化器没有类型!一个带括号的初始化器没有类型!没有类型对应于带括号的初始化器。”(引自 Scott Meyers)这就是为什么 C++11 和 C++14 中带有一个元素的带括号初始化器的自动类型推断无法遵循直观规则的原因。许多程序员认为这是标准中的缺陷。这就是为什么提案N3922:关于来自花括号初始化列表的新规则的auto推导存在的原因。特别地: 对于直接列表初始化:
  • 对于只有一个元素的大括号初始化列表,auto的推导将从该条目中推导出;
  • 对于具有多个元素的大括号初始化列表,auto的推导将无效。
不确定这是否会破坏现有的 C++14 代码。
来源:Scott Meyers在CppCon上就C++11/C++14/C++17中类型推断的怪癖进行了深入讨论,其中包括花括号初始化的自动类型推断(从29:00开始)。他在他的新书book中详细介绍了同样的内容(还有一个免费的样章包含该章节)。link

显然这是一个破坏性的变化。在这个变化之前,auto x { 1, 2 };是有效的,但在这个变化之后就会变成错误。而auto x { 1 };在这个变化之前是有效的,在这个变化之后则有不同的含义。 - user743382
@hvd 是的。让我们希望标准化委员会能够在代码直观性和与旧标准的兼容性之间找到一个折衷方案。 - Ivan Aksamentov - Drop
1
N3922在上次在厄巴纳的委员会会议上被投票通过成为工作文件。 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接