令人不安的评估顺序

YSC*_*YSC 7 c++ expression-evaluation

当我使用我最喜欢的容器时,我倾向于连锁操作.例如,在众所周知的Erase-remove成语中:

v.erase( std::remove_if(v.begin(), v.end(), is_odd), v.end() );
Run Code Online (Sandbox Code Playgroud)

根据我所知的评估顺序,v.end()(在rhs上)可能会调用之前进行评估std::remove_if.这不是问题,因为std::remove*只是在不改变其结束迭代器的情况下对矢量进行洗牌.

但它可能导致非常令人惊讶的结构,例如(演示):

#include <iostream>

struct Data
{
    int v;
    int value() const { return v; }
};

auto inc(Data& data)           { return ++data.v; }
void print_rhs(int, int value) { std::cout << value << '\n'; }

int main()
{
    Data data{0};
    print_rhs(inc(data), data.value()); // might print 0
}
Run Code Online (Sandbox Code Playgroud)

这是令人惊讶的,因为print_rhs被叫之后 inc被称为; 这意味着data.v1print_rhs被调用.然而,既然data.value()可能在之前进行评估,0那么可能就是输出.

如果评估顺序不那么令人惊讶,我认为这可能是一个很好的改进; 特别是如果在没有副作用的情况下评估具有副作用的函数的参数.

我的问题是:

  • 是否曾在C++委员会中讨论或建议过这种变化?
  • 你看到它可能带来什么问题吗?

Joh*_*nck 8

是否曾在C++委员会中讨论或建议过这种变化?

大概.

你看到它可能带来什么问题吗?

是.它可以减少当前存在的优化机会,除了编写更多单行代码的能力之外,它不会带来任何直接好处.但是单线并不是一件好事,所以这个提议可能永远不会超过-99分.