繁体   English   中英

GCC 无法区分 operator++() 和 operator++(int)

[英]GCC can't differentiate between operator++() and operator++(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++

[basic.lookup] (强调我的)

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

并且只有当查找是明确的时,才会进行重载解析。 在这种情况下,名称位于两个不同类的范围内,因此即使在重载解析之前也存在歧义。

[类.成员.查找]

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> {};

该名称现在位于单个类的范围内,并命名了两个重载。 查找成功,可以进行重载解析。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM