为什么C++不允许在条件运算符中使用隐式列表初始化?

12

这段代码可以编译:

std::string f(bool a, std::string const& b)
{
    if (a) return b;
    return {};
}

这段代码也可以编译:

std::string f(bool a, std::string const& b)
{
    return a ? b : std::string{};
}

这段代码无法编译:

std::string f(bool a, std::string const& b)
{
    return a ? b : {};
}

考虑到 ?: 操作符的两个结果值需要是相同类型,为什么它在第一个例子中可以推断类型,但在第二个例子中却不能推断类型呢?


看起来这个问题的答案可能与这个问题类似(基本上归结为“因为在编写语言规范时没有考虑到这个问题”)。然而我仍然认为保留这个问题是有用的,因为它本身的问题是不同的,仍然足够令人惊讶,并且其他问题在搜索这个问题时不会出现。


1
两种类型都需要可转换为相同的类型。{}没有类型。 - NathanOliver
2
clang提示{}是一个初始化列表(不能在此处使用) live: https://godbolt.org/z/imYL6q - Richard Critten
1
{} 替换为 std::initializer_list<char>() 也可以编译通过。 - jcai
1
也许这个问题可以转化为一份语言提案。 - M.M
@miral:正确的术语是“列表初始化”。这就是标准所称呼的;您在标准中找不到任何关于“统一初始化”的内容。 - Nicol Bolas
1个回答

6
一个括号初始化器不是一个表达式,因此它没有类型。请参见:

https://scottmeyers.blogspot.com/2014/03/if-braced-initializers-have-no-type-why.html

一种花括号初始化器是一种在标准中具有特殊规则的语法结构,明确指定了允许使用和类型推断。这些特殊规则之所以需要,正是因为花括号初始化器没有类型。在 ?: 语句中使用它们未经指定,因此程序无效。
如果你真的需要听到那个人连续三次说才能相信,那么:

https://youtu.be/wQxj20X-tIU?t=1792


1
@Miral "" 有一种类型。std::initializer_list<char>{} 也有一种类型。但 {} 没有。 - Nikos C.
2
@Miral: “它与任何类型兼容” 不是的。它是一种语法结构,在某些位置可以用于初始化特定类型的 prvalue。它并不“兼容”任何东西。 - Nicol Bolas
@Miral 那是因为标准明确允许这样做。大括号初始化没有类型,因此它们的使用必须由标准明确指定。在 ?: 中使用它从未被指定,因此该程序是非法的。 - Nikos C.
2
@NikosC:需要注意的是,花括号初始化列表没有类型,因为它们不是表达式。它们是与表达式不同的语法结构。因此,询问它们的类型就像询问它们的“值”或与表达式相关的任何其他事物一样。 - Nicol Bolas
1
我明白这不是编译器错误。但另一种解释这个问题的方式是“作为需求,它实际上有意义吗?”或者“有没有技术上无法完成的原因?” - xaxxon
显示剩余8条评论

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