GCC can't differentiate between operator++() and operator++(int)












59















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:



<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. Any ideas what could be wrong or how to work around this?










share|improve this question




















  • 6





    using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

    – Quentin
    Jan 8 at 12:11






  • 1





    fwiw also with supplying the implementation and also without crtp gcc reports the error

    – user463035818
    Jan 8 at 12:14








  • 3





    @Quentin Puts using declaration in a helper template PrePost : Pre, Post

    – felix
    Jan 8 at 12:16






  • 8





    For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

    – VTT
    Jan 8 at 12:17






  • 2





    It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

    – StoryTeller
    Jan 8 at 13:07
















59















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:



<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. Any ideas what could be wrong or how to work around this?










share|improve this question




















  • 6





    using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

    – Quentin
    Jan 8 at 12:11






  • 1





    fwiw also with supplying the implementation and also without crtp gcc reports the error

    – user463035818
    Jan 8 at 12:14








  • 3





    @Quentin Puts using declaration in a helper template PrePost : Pre, Post

    – felix
    Jan 8 at 12:16






  • 8





    For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

    – VTT
    Jan 8 at 12:17






  • 2





    It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

    – StoryTeller
    Jan 8 at 13:07














59












59








59


9






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:



<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. Any ideas what could be wrong or how to work around this?










share|improve this question
















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:



<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. Any ideas what could be wrong or how to work around this?







c++ operator-overloading multiple-inheritance ambiguous






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 8 at 16:30







jotik

















asked Jan 8 at 12:07









jotikjotik

8,64463792




8,64463792








  • 6





    using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

    – Quentin
    Jan 8 at 12:11






  • 1





    fwiw also with supplying the implementation and also without crtp gcc reports the error

    – user463035818
    Jan 8 at 12:14








  • 3





    @Quentin Puts using declaration in a helper template PrePost : Pre, Post

    – felix
    Jan 8 at 12:16






  • 8





    For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

    – VTT
    Jan 8 at 12:17






  • 2





    It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

    – StoryTeller
    Jan 8 at 13:07














  • 6





    using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

    – Quentin
    Jan 8 at 12:11






  • 1





    fwiw also with supplying the implementation and also without crtp gcc reports the error

    – user463035818
    Jan 8 at 12:14








  • 3





    @Quentin Puts using declaration in a helper template PrePost : Pre, Post

    – felix
    Jan 8 at 12:16






  • 8





    For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

    – VTT
    Jan 8 at 12:17






  • 2





    It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

    – StoryTeller
    Jan 8 at 13:07








6




6





using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

– Quentin
Jan 8 at 12:11





using Pre::operator++; using Post::operator++; works, but I guess it defeats the purpose of your CRTP...

– Quentin
Jan 8 at 12:11




1




1





fwiw also with supplying the implementation and also without crtp gcc reports the error

– user463035818
Jan 8 at 12:14







fwiw also with supplying the implementation and also without crtp gcc reports the error

– user463035818
Jan 8 at 12:14






3




3





@Quentin Puts using declaration in a helper template PrePost : Pre, Post

– felix
Jan 8 at 12:16





@Quentin Puts using declaration in a helper template PrePost : Pre, Post

– felix
Jan 8 at 12:16




8




8





For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

– VTT
Jan 8 at 12:17





For me behavior of gcc seems to be correct. Invocation of function operator ++ should not compile because it is not clear to which function does the name operator ++ refer to.

– VTT
Jan 8 at 12:17




2




2





It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

– StoryTeller
Jan 8 at 13:07





It's not a defect in the sense that the language itself has an inconsistency that needs resolution. It's only a design choice with unfortunate consequences, a colloquial defect, if you were.

– StoryTeller
Jan 8 at 13:07












1 Answer
1






active

oldest

votes


















63














Name lookup must occur first. In this case for the name operator++.




[basic.lookup] (emphasis mine)



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. Name lookup associates
the use of a name with a declaration ([basic.def]) of that name. Name
lookup shall find an unambiguous declaration for the name (see
[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]). Overload resolution ([over.match]) takes place after
name lookup has succeeded
. The access rules (Clause [class.access])
are considered only once name lookup and function overload resolution
(if applicable) have succeeded. 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]).




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. 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]. There is an ambiguity in your code. GCC is correct to report it.





As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class



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.






share|improve this answer





















  • 12





    Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

    – WhozCraig
    Jan 8 at 12:24








  • 4





    @StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

    – Arne Vogel
    Jan 8 at 12:30






  • 3





    Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

    – Walter
    Jan 8 at 12:33








  • 1





    @Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

    – StoryTeller
    Jan 8 at 12:41








  • 2





    @PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

    – StoryTeller
    Jan 8 at 20:24











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54091513%2fgcc-cant-differentiate-between-operator-and-operatorint%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









63














Name lookup must occur first. In this case for the name operator++.




[basic.lookup] (emphasis mine)



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. Name lookup associates
the use of a name with a declaration ([basic.def]) of that name. Name
lookup shall find an unambiguous declaration for the name (see
[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]). Overload resolution ([over.match]) takes place after
name lookup has succeeded
. The access rules (Clause [class.access])
are considered only once name lookup and function overload resolution
(if applicable) have succeeded. 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]).




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. 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]. There is an ambiguity in your code. GCC is correct to report it.





As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class



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.






share|improve this answer





















  • 12





    Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

    – WhozCraig
    Jan 8 at 12:24








  • 4





    @StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

    – Arne Vogel
    Jan 8 at 12:30






  • 3





    Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

    – Walter
    Jan 8 at 12:33








  • 1





    @Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

    – StoryTeller
    Jan 8 at 12:41








  • 2





    @PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

    – StoryTeller
    Jan 8 at 20:24
















63














Name lookup must occur first. In this case for the name operator++.




[basic.lookup] (emphasis mine)



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. Name lookup associates
the use of a name with a declaration ([basic.def]) of that name. Name
lookup shall find an unambiguous declaration for the name (see
[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]). Overload resolution ([over.match]) takes place after
name lookup has succeeded
. The access rules (Clause [class.access])
are considered only once name lookup and function overload resolution
(if applicable) have succeeded. 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]).




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. 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]. There is an ambiguity in your code. GCC is correct to report it.





As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class



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.






share|improve this answer





















  • 12





    Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

    – WhozCraig
    Jan 8 at 12:24








  • 4





    @StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

    – Arne Vogel
    Jan 8 at 12:30






  • 3





    Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

    – Walter
    Jan 8 at 12:33








  • 1





    @Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

    – StoryTeller
    Jan 8 at 12:41








  • 2





    @PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

    – StoryTeller
    Jan 8 at 20:24














63












63








63







Name lookup must occur first. In this case for the name operator++.




[basic.lookup] (emphasis mine)



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. Name lookup associates
the use of a name with a declaration ([basic.def]) of that name. Name
lookup shall find an unambiguous declaration for the name (see
[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]). Overload resolution ([over.match]) takes place after
name lookup has succeeded
. The access rules (Clause [class.access])
are considered only once name lookup and function overload resolution
(if applicable) have succeeded. 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]).




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. 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]. There is an ambiguity in your code. GCC is correct to report it.





As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class



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.






share|improve this answer















Name lookup must occur first. In this case for the name operator++.




[basic.lookup] (emphasis mine)



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. Name lookup associates
the use of a name with a declaration ([basic.def]) of that name. Name
lookup shall find an unambiguous declaration for the name (see
[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]). Overload resolution ([over.match]) takes place after
name lookup has succeeded
. The access rules (Clause [class.access])
are considered only once name lookup and function overload resolution
(if applicable) have succeeded. 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]).




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. 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]. There is an ambiguity in your code. GCC is correct to report it.





As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class



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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 8 at 12:25

























answered Jan 8 at 12:16









StoryTellerStoryTeller

97.2k12198264




97.2k12198264








  • 12





    Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

    – WhozCraig
    Jan 8 at 12:24








  • 4





    @StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

    – Arne Vogel
    Jan 8 at 12:30






  • 3





    Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

    – Walter
    Jan 8 at 12:33








  • 1





    @Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

    – StoryTeller
    Jan 8 at 12:41








  • 2





    @PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

    – StoryTeller
    Jan 8 at 20:24














  • 12





    Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

    – WhozCraig
    Jan 8 at 12:24








  • 4





    @StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

    – Arne Vogel
    Jan 8 at 12:30






  • 3





    Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

    – Walter
    Jan 8 at 12:33








  • 1





    @Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

    – StoryTeller
    Jan 8 at 12:41








  • 2





    @PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

    – StoryTeller
    Jan 8 at 20:24








12




12





Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

– WhozCraig
Jan 8 at 12:24







Fwiw, MS VS2015 (19.00.24215.1) complains about the ambiguity via IntelliNonsense, but then still compiles the code to success (with no warnings or errors) and executes the hoped-for members at run-time.

– WhozCraig
Jan 8 at 12:24






4




4





@StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

– Arne Vogel
Jan 8 at 12:30





@StoryTeller Indeed, for a "normal" method f() vs. f(int), clang++ complains about: "error: member 'f' found in multiple base classes of different types" and adds "note: member found by ambiguous name lookup". GCC is actually more consistent here.

– Arne Vogel
Jan 8 at 12:30




3




3





Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

– Walter
Jan 8 at 12:33







Ok. So it appears that this is sort-of a defect in the language (that d++ and ++d refer to the same operator/function name), which gcc faithfully implements, while clang and VS17 appear to implement what the user obviously intended (even w/o warning).

– Walter
Jan 8 at 12:33






1




1





@Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

– StoryTeller
Jan 8 at 12:41







@Walter - Pretty much. Had we taken a path like, say, Python with regards to overloading, it'd had probably been easier to work with all around. Alas, something else was choesn.

– StoryTeller
Jan 8 at 12:41






2




2





@PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

– StoryTeller
Jan 8 at 20:24





@PiotrNycz - Other than being called by a special syntax, overloaded operators are regular functions. As a matter of fact, they can also be called just like regular functions. d.operator++(0) will cause this ambiguity, as should d++, since the two are exactly equivalent.

– StoryTeller
Jan 8 at 20:24


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54091513%2fgcc-cant-differentiate-between-operator-and-operatorint%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

How to fix TextFormField cause rebuild widget in Flutter

Npm cannot find a required file even through it is in the searched directory