C++中的三元运算符产生什么对象?

What object is produced by ternary operator in C++?

下面的程序

#include <optional>
#include <iostream>

int main()
{
    std::optional<int> a;
    constexpr bool x = true;

    const std::optional<int> & b = x ? a : std::nullopt;
    std::cout << (&a == &b);

    const std::optional<int> & c = x ? a : (const std::optional<int> &)std::nullopt;
    std::cout << (&a == &c);

    const std::optional<int> & d = x ? a : (const std::optional<int>)std::nullopt;
    std::cout << (&a == &d);
}

打印 010 即使在编译器优化的情况下: https://gcc.godbolt.org/z/asTrzdE3c

能否请您解释一下为什么会这样,看似相同的3个案例有什么区别?

用外行的话来说,三元运算符将 return 一个类型的对象,两个操作数都可以隐式转换为该对象(花絮:这就是为什么它在元函数 std::common_type 的幕后使用的原因).

如果两个操作数都是通用类型,您将获得对所选操作数的引用。如果没有,将创建所需类型的临时对象。你的第一个和第三个例子就是这种情况。

首先你必须弄清楚三元运算符结果的类型是什么。

x ? a : std::nullopt;

这里的a是可以引用的变量,std::nullopt是隐式转换为匹配类型可选的东西(这里是std::optional<int>)。 因此 std::nullopt 的转换以创建临时值结束。为了匹配类型 a 也被复制。

所以三元运算符将类型推断为 std::optional<int> 类型的值,它成为一个临时对象。 std::optional<int> 的新实例已创建。

现在const auto &可以延长临时对象的生命周期。所以 b 是对 std::optional<int> 的引用,它是延长生命周期的临时值。

d 是相同的场景,但更明确。

c(const std::optional<int> &)std::nullopt,它创建了 std::optional<int> 的临时对象,具有延长的生命周期。这里三元运算符的参数是 std::optional<int>&const std::optional<int>&,因此它能够传递第一个参数引用 return 类型。

看看 cppinsights generates 你的代码是什么:

#include <optional>
#include <iostream>

int main()
{
  std::optional<int> a = std::optional<int>();
  constexpr const bool x = true;
  const std::optional<int> & b = x ? std::optional<int>(a) : std::optional<int>(std::nullopt_t(std::nullopt));
  std::cout.operator<<((&a == &b));
  const std::optional<int> & c = x ? a : static_cast<const std::optional<int>>(std::optional<int>(std::nullopt_t(std::nullopt)));
  std::cout.operator<<((&a == &c));
  const std::optional<int> & d = (x ? std::optional<int>(a) : static_cast<const std::optional<int>>(std::optional<int>(std::nullopt_t(std::nullopt))));
  std::cout.operator<<((&a == &d));
}