【问题标题】:what is the result (type) of ternary operation?三元运算的结果(类型)是什么?
【发布时间】:2017-07-12 17:11:50
【问题描述】:

三元运算是否返回副本或引用?

我检查了以下代码

vector<int> v0 = { 1, 2 };
vector<int> v1 = { 3 };

vector<int>& v = true ? v0 : v1;
v.clear(); // v0 will be cleared also

我认为三元运算会返回v0 的副本。然后将其传递给v。因此vv0 具有不同的数据存储方式。测试没有显示出来。

谢谢,Kerrek SB!我添加了一个“不应该编译”的示例(感谢 WhiZTiM!)来说明这一点。

vector<int>& v = true ? v0 : vector<int>{3};
v.clear(); // v0 will not be cleared

【问题讨论】:

  • 你问的不是类型,而是值类别!
  • 什么是价值类别?
  • v 是一个引用 - 一个对 v0 的引用,所以 v0 是您通过该引用清除的内容。

标签: c++ ternary-operator


【解决方案1】:

条件表达式的类型是操作数的通用类型。

但我认为您实际上对此并不感兴趣。重要的是条件表达式的值类别是什么。

如果两个操作数都是或可以转换为公共类型的左值,则条件表达式是左值;否则它是一个右值(可能需要对其中一个操作数进行左值到右值的转换)。

【讨论】:

  • (还有一些细节,因为值类别的范围比我说的要好,您也可以在其中一个操作数中包含throw。但这是要点。)
  • 这里有点微妙的愚蠢。考虑const int&amp; f(const int&amp; n) { return n; }。我们都知道const int&amp; r = f(5); 是一个悬空引用。现在考虑const int&amp; r = cond ? f(5) : f(-5);。出于同样的原因,这是一个悬空的参考。但const int&amp; r = cond ? 5 : f(-5); 不是,因为该条件表达式是纯右值并且临时值的生命周期延长了。
【解决方案2】:

规则找到here: 与你的表达相关:

E1 ? E2 : E3

4) 如果 E2 和 E3 是 glvalues 的相同类型和相同的值 类别,则结果具有相同的类型和值类别,并且是 如果 E2 和 E3 中的至少一个是位域,则为位域。

在你的情况下:

true ? v0 : v1;

v0v1lvalues(广义上为 glvalue)。 所以返回将是一个 lvalue v0。因此,您的表达式将等同于:

vector<int>& v = v0;

至于您的编辑

vector<int>& v = true ? v0 : vector<int>{3};
v.clear(); // v0 will not be cleared

Should not compile,因为结果的值类别将是rvalue,您不能将非常量引用绑定到rvalue

【讨论】:

  • MSVC 编译。编译器错误?
  • @user1899020 是的,但微软更喜欢将该错误称为“编译器扩展”。禁用它,这很危险。
  • @user1899020:不,这不是错误,它是编译器扩展Everybody 将其称为编译器扩展,而不仅仅是 Microsoft。 (因为它显然只是一个简单的编译器扩展。)不,它并不比标准 C++ 的生命周期扩展规则更危险,用于与 const 引用相关的临时对象。 Microsoft 扩展只是使 const 可选。
猜你喜欢
  • 1970-01-01
  • 2015-08-12
  • 2016-06-26
  • 1970-01-01
  • 2011-12-17
  • 2010-11-20
  • 1970-01-01
  • 2015-09-21
  • 2020-11-05
相关资源
最近更新 更多