具有无效类型的分支的三元运算符

LmT*_*oon 10 c++ conditional-operator compiler-optimization

使用返回void的函数的三元运算符是否安全?像这样的东西:

void foo1(){}
void foo2(){}

//////////////

bool to_use_1 = ....;
to_use_1 ? foo1() : foo2();
Run Code Online (Sandbox Code Playgroud)

编译器可以删除此代码吗?假设它会将这些函数视为纯函数,并执行删除这些调用的激励优化

Lig*_*ica 7

首先,编译器将/应该从逻辑上"删除"任何具有可观察效果的调用(除了复制省略之外).无论优化模式多么激进,这都不是它允许做的事情.

事实上,C++标准明确允许条件运算符的操作数的结果void,因此这是预期和安全的.但是,它确实必须是两者.

[C++14: 5.16/1]:条件表达式从右到左分组.第一个表达式在上下文中转换为bool(第4条).它被评估,如果是,则条件表达式的结果是第二个表达式的值,否则是第三个表达式的值.仅评估第二和第三表达式中的一个.在与第二或第三表达式相关联的每个值计算和副作用之前,对与第一表达式相关联的每个值计算和副作用进行排序.

[C++14: 5.16/2]:如果第二个或第三个操作数具有类型void,则以下之一应保持:

  • 第二个或第三个操作数(但不是两个)是一个(可能带括号的)throw-expression(15.1); 结果是另一个的类型和值类别.

  • 第二个和第三个操作数都有类型void; 结果是类型void,是一个prvalue. [注意:这包括两个操作数都是throw-expressions的情况. - 尾注]

从技术上讲,这一措辞(在谈"值")不完全拼出来的是完全相同的第二个和第三个表达式的一个评估,即使这些评价没有"价值".但从分析的角度来看,它基本上是无可争辩的.这里可能有一个编辑改进的案例.

请注意,这些都不能保证您的计算机在执行期间实际上会跳转到foo1foo2; 在您给出的具体示例中,编译器可以立即看到两个函数都是完全空的,并优化掉整行代码.但这不会影响程序的语义,也不会影响条件运算符的使用.