如何解决左值和右值混合使用的三元运算符的类型推导
最近,我偶然发现自己的代码是这样写的(这里简化了很多):
#include <iostream>
#include <string>
void foo(std::string&& value)
{
std::cout << value << std::endl;
// for instance modify value here somehow optionally and move it further on ...
// foo2(std::move(value));
}
int main()
{
std::string value = "Hello world";
for (size_t idx = 0; idx < 2; ++idx)
{
foo(idx < 1 ? value : std::move(value));
}
}
请不要对有问题的计划发表评论!这发生在一个漫长的夜晚会议... :)
我只想知道,就标准行为而言,这里实际发生了什么。三元运算符的类型推导显然会导致右值,但我想知道标准中的确切拟合短语,因为可观察到的效果是对于 idx
我读了 https://timsong-cpp.github.io/cppwp/n4659/expr.cond 但这似乎不足以解释这里的行为,因为我期望直接右值转换(虽然最初我期望编译器错误)。我还认为这里可能有一些关于此的重复,但到目前为止我无法在这里找到真正合适的。但是,如果有相当快的可检测到的,请提前抱歉!
解决方法
我是这样看的:
idx < 1 ? value : std::move(value)
是一个表达式。
计算这个表达式的结果是一个右值总是。
在 idx < 1
的情况下:由该表达式计算的 rvalue 由 value
中的 copy-constructing 构造。
在 idx >=
的情况下:由该表达式计算的 rvalue 由 move-constructing
中的 value
构造。
所以最后,void foo(std::string&& value)
中的函数参数值总是通过计算这个表达式绑定到一个右值。
只是这个表达式值本身的构造方式不同:第一种情况是通过复制构造,第二种情况是通过移动构造。
,根据 cppinsights.io,编译器正在创建临时 std::string
。
foo((idx < 1 ? std::basic_string<char,std::char_traits<char>,std::allocator<char> >(value) : std::basic_string<char,std::allocator<char> >(std::move(value))));
这里是将三元运算符与函数调用分开的版本:
auto&& x = idx < 1 ? value : std::move(value);
foo(std::move(x));
std::basic_string<char,std::allocator<char> > && x = (idx < 1 ? std::basic_string<char,std::allocator<char> >(std::move(value)));
foo(std::move(x));
我试图理解阅读标准 n4835.pdf,我希望这是正确的:
7.6.16 条件运算符 [expr.cond]
4 否则,如果第二个和第三个操作数具有不同的类型并且具有(可能有 cv 限定的)类类型,或者如果两者都是相同值类别和相同类型的泛左值,除了 cv 限定,尝试形成从每个操作数到另一个操作数的类型的隐式转换序列 (12.4.3.1)。 [...] 尝试形成从 T1 类型的操作数表达式 E1 到与操作数表达式 E2 的类型 T2 相关的目标类型的隐式转换序列,如下所示:
(4.1) — 如果 E2 是左值,则目标类型是“对 T2 的左值引用”,受制于在转换中引用必须直接绑定 (9.4.3) 到泛左值的约束。
(4.2) — 如果 E2 是 xvalue,则目标类型是“对 T2 的右值引用”,受引用必须直接绑定的约束。
(4.3) — 如果 E2 是纯右值,或者如果上述转换序列都不能形成并且至少一个操作数具有(可能是 cv 限定的)类类型:
[...]
(4.3.3) — 否则,目标类型是 E2 在应用左值到右值后的类型 (7.3.1),
4.1 和 4.2 不适用,所以我们来到 4.3.3。到 7.3.1,其中 3.2 适用。
7.3.1 左值到右值的转换 [conv.lval]
3 转换结果根据以下规则确定:
[...]
(3.2) — 否则,如果 T 具有类类型,则转换会从泛左值复制初始化结果对象。
请注意,7.6.16 4 说转换是双向尝试的,因此不要过多关注 4.3(.3) 中的“E2”。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。