C ++: Ассоциативность оператора * (умножение) не слева направо

Работая над школьным заданием, мы должны были что-то делать с перегрузкой операторов и шаблонами. Все круто Я написал:

template<class T>
class Multiplication : public Expression<T>
{
private:
typename std::shared_ptr<Expression<T> > l, r;

public:
Multiplication(typename std::shared_ptr<Expression<T> > l, typename std::shared_ptr<Expression<T> > r) : l(l), r(r) {};
virtual ~Multiplication() {};

T evaluate() const
{
std::cout << "*";
T ml = l->evaluate();
T mr = r->evaluate();
return ml * mr;
};
};

Затем один из друзей спросил меня, почему его код выводит данные в «неправильном» порядке.
У него было что-то вроде

T evaluate() const
{
std::cout << "*";
return l->evaluate() * r->evaluate();
};

Код r->evaluate() распечатал отладочную информацию, прежде чем l->evaluate(),
Я также проверил это на своей машине, просто изменив эти три строки на одну строку.

Итак, я подумал, ну тогда * должен быть справа налево ассоциативным. Но везде в интернете говорят, что это слева направо. Есть ли дополнительные правила? Может быть, что-то особенное при использовании шаблонов? Или это ошибка в VS2012?

2

Решение

Когда мы говорим, ассоциативность * слева направо, мы имеем в виду, что выражение a*b*c*d всегда будет оценивать как (((a*b)*c)*d), Вот и все. В вашем примере у вас есть только один operator*так что нечего связывать.

То, с чем вы сталкиваетесь, является порядком оценки операндов. Ты звонишь:

operator*(l->evaluate(), r->evaluate());

Оба выражения должны быть оценены перед вызовом operator*, но это не определено (явно) стандартом C ++, в каком порядке они оцениваются. В вашем случае, r->evaluate() оценили в первую очередь — но это не имеет ничего общего с ассоциативностью operator*,

Обратите внимание, что даже если у вас было a->evaluate() * b->evaluate() * c->evaluate(), который будет проанализирован как:

operator*(operator*(a->evaluate(), b->evaluate()), c->evaluate())

основанный на правилах ассоциативности операторов — но даже в этом случае нет никаких правил, чтобы предотвратить c->evaluate() быть вызванным первым. Это может быть очень хорошо!

8

Другие решения

У вас есть один оператор в вашем выражении:

l->evaluate() * r->evaluate()

поэтому ассоциативность здесь вообще не задействована. Уловка в том, что два операнда вычисляются перед вызовом * оператор и порядок, в котором они оцениваются, не определены. Компилятору разрешается изменять порядок оценки любым подходящим способом.

В терминах C ++ 11 вызов operator* секвенируется после оценки операнда, но между этими двумя оценками нет отношения последовательности. От черновик n4296 (пост C ++ 14), страница 10:

§1.9.15 За исключением отмеченных случаев, оценки операндов отдельных операторов и подвыражений отдельных выражений не являются последовательными.

2

По вопросам рекламы [email protected]