GCC 无法区分运算符++() 和运算符++(int)


template <typename CRTP>
struct Pre {
CRTP & operator++();
};
template <typename CRTP>
struct Post {
CRTP operator++(int);
};
struct Derived
: Pre<Derived>
, Post<Derived>
{};
int main() {
Derived d;
d++;
++d;
}

我从GCC得到这些错误:

<source>: In function 'int main()':
<source>:18:10: error: request for member 'operator++' is ambiguous
d++;
^~
<source>:8:14: note: candidates are: CRTP Post<CRTP>::operator++(int) [with CRTP = Derived]
CRTP operator++(int);
^~~~~~~~
<source>:3:16: note:                 CRTP& Pre<CRTP>::operator++() [with CRTP = Derived]
CRTP & operator++();
^~~~~~~~
<source>:19:11: error: request for member 'operator++' is ambiguous
++d;
^
<source>:8:14: note: candidates are: CRTP Post<CRTP>::operator++(int) [with CRTP = Derived]
CRTP operator++(int);
^~~~~~~~
<source>:3:16: note:                 CRTP& Pre<CRTP>::operator++() [with CRTP = Derived]
CRTP & operator++();
^~~~~~~~

预减量和后减量运算符会导致类似的错误。Clang没有这样的错误。有什么想法可能是错误的,或者如何解决这个问题吗?

必须首先进行名称查找。在这种情况下,名称为operator++

[基本查找](强调挖掘)

1名称查找规则统一适用于所有名称(包括typedef名称([dcl.typedef])、命名空间名称([basic.namespace]),和类名([class.name])),只要语法允许在特定规则所讨论的上下文中。名称查找关联将一个名称与该名称的声明(〔basic.def〕)一起使用名称查找应找到名称的明确声明(请参阅[class.member.lookup])。名称查找可能关联多个如果发现名称是函数名称,则使用名称声明;声明被认为形成了一组重载函数([over.load])。过载解析([over.match])发生在名称查找已成功。访问规则(条款[class.access])仅考虑一次名称查找和函数重载解析(如适用)已成功。仅在名称查找之后,函数过载解决(如果适用)和访问检查已成功名称声明引入的属性是否被进一步使用在表达式处理中(子句[expr])。

只有在查找明确的情况下,才会继续进行过载解析。在这种情况下,名称是在两个不同类的范围内找到的,因此即使在重载解析之前也会出现歧义。

[class.member.lookup]

8如果明确地找到了重载函数的名称,重载解析([over.match])也发生在访问之前控制歧义通常可以通过将名称限定为其类名。[示例:

struct A {
int f();
};
struct B {
int f();
};
struct C : A, B {
int f() { return A::f() + B::f(); }
};

--结束示例]

该示例大致总结了[class.member.lookup]前面段落中相当长的查找规则。您的代码中存在歧义。GCC报告它是正确的。


关于解决这一问题,人们在评论中已经提出了解决方法的想法。添加一个助手CRTP类

template <class CRTP>
struct PrePost
: Pre<CRTP>
, Post<CRTP>
{
using Pre<CRTP>::operator++;
using Post<CRTP>::operator++;
};
struct Derived : PrePost<Derived> {};

该名称现在位于单个类的作用域中,并命名两个重载。查找成功,可以继续解决过载问题。

最新更新