Имеет ли перегруженный побитовый оператор или оператор ('|') четко определенный порядок вычисления?
Если мой класс C++ перегружен оператором побитового ИЛИ (|
), гарантирует ли спецификация языка C++, что аргументы, передаваемые в серию вызовов этого оператора, будут оцениваться слева направо? Или порядок оценки определяется (или не определен)?
(IIRC C++ встроенный |
оператор имеет определенный порядок реализации; но, может быть, все по-другому, когда оператор перегружен для класса?)
Ниже приведена программа, которая иллюстрирует то, что я спрашиваю: гарантированно ли эта программа распечатывает 0 1 2 3 4
(как это происходит на Mac, на котором я сейчас сижу), или это может быть распечатано на законных основаниях 4 3 2 1 0
(или какой-то другой порядок) в определенных условиях?
#include <iostream>
class mytype_t
{
public:
mytype_t(int v) : _val(v) {/* empty */}
mytype_t operator | (const mytype_t & rhs) const {return (_val | rhs._val);}
private:
int _val;
};
mytype_t func(int v)
{
std::cout << v << std::endl;
return mytype_t(v);
}
int main(int, char **)
{
mytype_t x = func(0) | func(1) | func(2) | func(3) | func(4);
return 0;
}
1 ответ
Если встроенный оператор предписывает конкретную последовательность, аргументы оцениваются в том же порядке и для перегрузки. Вот соответствующий абзац (из n4659, проект C++17), выделение мое:
[over.match.oper]
2 Если любой операнд имеет тип, который является классом или перечислением, может быть объявлена пользовательская функция оператора, которая реализует этот оператор, или может потребоваться пользовательское преобразование для преобразования операнда в тип, подходящий для встроенного оператор В этом случае разрешение перегрузки используется для определения того, какая операторская функция или встроенный оператор должны вызываться для реализации оператора. Поэтому запись оператора сначала преобразуется в эквивалентную запись вызова функции, как показано в Таблице 12 (где @ обозначает один из операторов, охватываемых указанным подпунктом). Однако операнды упорядочены в порядке, установленном для встроенного оператора (пункт [expr]).
Так нет, перегружен operator|
не будет иметь четко определенный порядок оценки, потому что встроенный не имеет.