2

以下程序

#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 个案例之间有什么区别?

4

2 回答 2

3

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

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

于 2021-07-08T15:55:15.487 回答
2

首先,您必须了解三元运算符结果的类型是什么。

x ? a : std::nullopt;

a是可以引用的变量,并且std::nullopt是隐式转换为匹配类型的可选内容(此处std::optional<int>)。因此,转换std::nullopt以创造临时价值而告终。匹配类型a也被复制。

因此,三元运算符将 type 推导出为类型的值,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>&因此它能够传递第一个参数引用返回类型。

查看cppinsights使用您的代码生成的内容:

#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));
}
于 2021-07-08T15:57:28.423 回答