2

При работе над заданием школы нам нужно было что-то сделать с перегрузкой оператора и шаблонами. Все круто. Я написал: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?

+7

Ассоциативность не совпадает с порядком оценки. –

+0

Кажется, что это ключ :) Я сделаю некоторые исследования, спасибо уже. –

+0

Возможный дубликат [Приоритет оператора по отношению к порядку оценки] (http: // stackoverflow.com/questions/5473107/operator-priorence-vs-order-of-evaluation) –

ответ

8

Когда мы говорим, ассоциативность * слева направо, мы имеем в виду, что выражение 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() от вызова первым. Это может быть очень хорошо!

+0

Спасибо, человек! Имеет смысл! :) –

2

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

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

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

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

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

Смежные вопросы