简体   繁体   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;
}

I get these errors from GCC:我从 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++();
                ^~~~~~~~

Pre-decrement and post-decrement operators cause similar errors.前自减和后自减运算符会导致类似的错误。 No such errors with Clang. Clang 没有这样的错误。 Any ideas what could be wrong or how to work around this?任何想法可能是错误的或如何解决这个问题?

Name lookup must occur first.名称查找必须首先发生。 In this case for the name operator++ .在这种情况下,名称为operator++

[basic.lookup] (emphasis mine) [basic.lookup] (强调我的)

1 The name lookup rules apply uniformly to all names (including typedef-names ([dcl.typedef]), namespace-names ([basic.namespace]), and class-names ([class.name])) wherever the grammar allows such names in the context discussed by a particular rule. 1名称查找规则统一适用于语法允许的所有名称(包括 typedef-names ([dcl.typedef])、namespace-names ([basic.namespace]) 和 class-names ([class.name]))特定规则讨论的上下文中的此类名称。 Name lookup associates the use of a name with a declaration ([basic.def]) of that name.名称查找将名称的使用与该名称的声明 ([basic.def]) 相关联。 Name lookup shall find an unambiguous declaration for the name (see [class.member.lookup]) .名称查找应为名称找到一个明确的声明(参见 [class.member.lookup]) Name lookup may associate more than one declaration with a name if it finds the name to be a function name;如果名称查找发现名称是函数名称,则名称查找可能会将多个声明与名称相关联; the declarations are said to form a set of overloaded functions ([over.load]).声明被称为形成一组重载函数([over.load])。 Overload resolution ([over.match]) takes place after name lookup has succeeded .重载解析 ([over.match]) 在名称查找成功后发生 The access rules (Clause [class.access]) are considered only once name lookup and function overload resolution (if applicable) have succeeded.仅在名称查找和函数重载解析(如果适用)成功后才考虑访问规则(条款 [class.access])。 Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name's declaration used further in expression processing (Clause [expr]).只有在名称查找、函数重载解析(如果适用)和访问检查成功之后,名称声明引入的属性才会进一步用于表达式处理(条款 [expr])。

And only if the lookup is unambiguous, will overload resolution proceed.并且只有当查找是明确的时,才会进行重载解析。 In this case, the name is found in the scope of two different classes, and so an ambiguity is present even prior to overload resolution.在这种情况下,名称位于两个不同类的范围内,因此即使在重载解析之前也存在歧义。

[class.member.lookup] [类.成员.查找]

8 If the name of an overloaded function is unambiguously found, overloading resolution ([over.match]) also takes place before access control. 8如果明确找到重载函数的名称,重载解析([over.match])也会在访问控制之前发生。 Ambiguities can often be resolved by qualifying a name with its class name.歧义通常可以通过用类名限定名称来解决。 [ Example: [ 例子:

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

— end example ] — 结束示例 ]

The example pretty much summarizes the rather long lookup rules in the previous paragraphs of [class.member.lookup].该示例几乎总结了 [class.member.lookup] 前面段落中相当长的查找规则。 There is an ambiguity in your code.您的代码中存在歧义。 GCC is correct to report it. GCC 报告它是正确的。


As for working around this, people in comments already presented the ideas for a workaround.至于解决这个问题,评论中的人已经提出了解决方法的想法。 Add a helper CRTP class添加辅助 CRTP 类

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

struct Derived : PrePost<Derived> {};

The name is now found in the scope of a single class, and names both overloads.该名称现在位于单个类的范围内,并命名了两个重载。 Lookup is successful, and overload resolution may proceed.查找成功,可以进行重载解析。

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

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