Давайте возьмем несколько примеров кода:
! 4 > 0;
Из стандарта C ++ мы знаем, что сначала будет выполнено отрицание, чем сравнение. Но если мы немного расширим этот пример:
#include <iostream>
class Test
{
public:
bool operator!() const
{
std::cout << "operator!" << std::endl;
return false;
}
bool operator>(const int &) const
{
std::cout << "operator>" << std::endl;
return false;
}
};int main(int argc, char * argv[])
{
Test t;
std::cout << "t > 0;" << std::endl;
t > 0;
std::cout << "! t > 0;" << std::endl;
! t > 0;
std::cout << "!t.operator>(0)" << std::endl;
! t.operator>(0);
return 0;
}
Выход этой программы будет:
t > 0;
operator>
! t > 0;
operator!
!t.operator>(0)
operator>
И тут всплывает мой вопрос. Зачем SomeObjInstance > 0
звонок отличается от SomeObjInstance.operator>(0)
, Я знаю, что не принято вызывать операторов вторым способом (в качестве участников), но почему эти вызовы отличаются? Я всегда так думал SomeObjInstance > 0
переводится под капотом на членский вызов SomeObjInstance.operator>(0)
или вызов функции bool operator>(const Test &, int)
если член оператора нет.
Где это поведение описано в стандарте C ++, или, может быть, это какое-то неопределенное поведение?
Оператор членского доступа .*
имеет более высокий приоритет, чем оператор отрицания !
,
Где это поведение описано в стандарте C ++, или, может быть, это какое-то неопределенное поведение?
Скорее всего, это соответствующий пункт:
13.5 Перегруженные операторы [over.oper]
5) операторские функции обычно не вызываются напрямую; вместо этого они вызываются для оценки операторов, которые они реализуют (13.5.1 — 13.5.7). Однако их можно вызывать явно, используя идентификатор оператора-функции в качестве имени функции в синтаксисе вызова функции (5.2.2).
В вашем первом примере t > 0;
он будет использовать соответствующий оператор с приоритетом для операторов реляционного сравнения. Тем не менее, в вашей второй версии t.operator>(0)
Вы используете это как вызов функции. Тем самым Test::operator>
используется в качестве функции-члена, что приведет к описанному вами поведению, поскольку оно теряет свои операторские характеристики («однако их можно вызывать явно, используя идентификатор оператора-функции в качестве имени функции в синтаксисе вызова функции»).
Смотрите также:
Просто на минуту наденьте шляпу компилятора. Вам необходимо проанализировать и оценить выражение в соответствии с четким набором правил (включая приоритет оператора). Тот факт, что оценка включает в себя вызов функции-члена ( operator>()
), который также был бы вызван, если бы выражение использовало оператор >
— И что? Вы хотите сделать специальный случай и предположить, что в этом случае приоритет по умолчанию должен быть изменен? И как далеко вы готовы пойти с этим? Например. если этот метод вызывается косвенно или указателем на функцию? Я думаю, что это усложнит логику компилятора и все же позволит привести не интуитивные примеры, аналогичные вашему первоначальному вопросу.
.
а также ()
иметь более высокий приоритет, чем !
, Синтаксис оператора анализируется как
(!t) > 0;
в то время как явный вызов анализируется как
!((t.operator>)())