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));
}
下面的程序
#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));
}