3

让我们看一些代码示例:

! 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>
  1. 第一次调用(控制调用)很清楚。我们检查是否调用了我们想要的运算符。
  2. 第二个电话是我首先陈述的证明。首先调用否定运算符,然后调用结果(布尔)运算符>。
  3. 第三个电话是困扰我的。

这里提出了我的问题。为什么SomeObjInstance > 0call 不同于SomeObjInstance.operator>(0). 我知道以第二种方式(作为成员)调用操作员并不常见,但为什么这种调用不同?如果成员操作员不存在,我总是坚持将SomeObjInstance > 0其转换为成员调用SomeObjInstance.operator>(0)或函数调用。bool operator>(const Test &, int)

在 C++ 标准中描述了这种行为,或者这可能是某种未定义的行为?

4

3 回答 3

6

成员访问运算符.*的优先级高于否定运算符!

在 C++ 标准中描述了这种行为,或者这可能是某种未定义的行为?

这很可能是相关段落:

13.5 重载运算符 [over.oper]

5) 通常不直接调用操作符函数;相反,它们被调用来评估它们实现的运算符 (13.5.1 – 13.5.7)。但是,可以使用 operator-function-id 作为函数调用语法 (5.2.2) 中的函数名称来显式调用它们。

在您的第一个示例t > 0;中,它将使用具有优先级的相应运算符作为关系比较运算符。但是,在您的第二个版本中,t.operator>(0)您将其用作函数调用。因此,Test::operator>它被用作成员函数,这将导致您描述的行为,因为它失去了它的操作符特征(“它们可以被显式调用,但是,在函数调用中使用 operator-function-id 作为函数的名称语法”)。

也可以看看:

于 2012-11-13T12:21:51.513 回答
2

戴上你的编译器帽子一会儿。您需要根据一组明确的规则(包括运算符优先级)解析和评估表达式。评估涉及调用成员函数 ( operator>()) 的事实,如果表达式使用运算符,该函数也会被调用>- 那又如何?您是否想创建一个特殊情况并假设在这种情况下应该更改默认优先级?你准备走多远?例如,如果此方法是间接调用的,还是由函数指针调用的?我认为这会使编译器的逻辑复杂化,并且仍然允许违反直觉的示例,类似于您的原始问题。

于 2012-11-13T12:42:35.667 回答
1

.并且()具有比 更高的优先级!。运算符语法被解析为

(!t) > 0;

而显式调用被解析为

!((t.operator>)())
于 2012-11-13T12:23:22.430 回答