Когда я работаю с моими любимыми контейнерами, я склонен к цепным операциям. Например, в известной идиоме Erase – remove :
v.erase( std::remove_if(v.begin(), v.end(), is_odd), v.end() );
Из того, что я знаю о порядке оценки, v.end()
(по rhs) может быть оценено до вызова std::remove_if
. Здесь это не проблема, поскольку std::remove*
только перетасовывает вектор без изменения его конечного итератора.
Но это может привести к действительно удивительным конструкциям, например, ( demo ):
#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
}
Это удивительно, поскольку print_rhs
называется после вызова inc
; что означает data.v
= 1
, когда вызывается print_rhs
. Тем не менее, поскольку data.value()
может быть оценено до , возможен вывод 0
.
Я думаю, что это может быть хорошим улучшением, если порядок оценки будет менее удивительным; в частности, если аргументы функции с побочными эффектами оценивались раньше, чем аргументы без.
Мои вопросы:
- Обсуждали ли когда-нибудь это изменение или предложили в комитете по С ++?
- Видите ли вы какие-либо проблемы, которые это может принести?