【问题标题】:What object is produced by ternary operator in C++?C++中的三元运算符生成什么对象?
【发布时间】:2021-09-19 01:57:03
【问题描述】:

下面的程序

#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);
}

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

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

【问题讨论】:

  • 请参阅 条件运算符 en.cppreference.com/w/cpp/language/operator_other,因为它大约有 2 页的“if-this-then-that”
  • 作为另一个数据点,如果您直接比较选项(而不是获取它们的地址),它将打印111
  • 通俗地说,三元运算符将返回一个类型的对象,两个操作数都可以隐式转换(这就是为什么它在元函数std::common_type的幕后使用)。如果两个操作数都是通用类型,您将获得对所选操作数的引用。如果没有,将创建所需类型的临时对象。在您的第一个和第三个示例中就是这种情况。
  • @SergeyA 听起来像是一个答案。
  • @TedLyngmo 我觉得作为一个答案有点缺乏规范,但如果人们认为它有用,我可以发布它。

标签: c++ conditional-operator stdoptional


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    x ? a : std::nullopt;
    

    这里a 是可以引用的变量,std::nullopt 是隐式转换为可选匹配类型的东西(这里是std::optional&lt;int&gt;)。 所以std::nullopt 的转换以临时价值的创造结束。匹配类型a 也被复制。

    所以三元运算符将 type 推导出为 std::optional&lt;int&gt; 类型的值,它成为一个临时对象。 std::optional&lt;int&gt; 的新实例已创建。

    现在const auto &amp; 能够延长临时对象的生命周期。所以b 是对std::optional&lt;int&gt; 的引用,这是一个临时的延长寿命。

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

    c 具有(const std::optional&lt;int&gt; &amp;)std::nullopt,它创建了具有延长寿命的std::optional&lt;int&gt; 的临时对象。这里的三元运算符有 std::optional&lt;int&gt;&amp;const std::optional&lt;int&gt;&amp; 作为参数,因此它能够传递第一个参数引用返回类型。

    查看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));
    }
    

    【讨论】:

    • 这段代码(由 cppinsignt 生成)不等价,它打印000
    • 工具有一个字符的错误。添加&amp;fixes issue
    猜你喜欢
    • 2017-08-14
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2021-10-25
    • 2011-03-16
    相关资源
    最近更新 更多