Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

operator++ as both a postfix and prefix doesn't work with clang

I tried to write an operator that can be used both as a prefix and a postfix operator

#include <iostream> #include <utility>  struct B {    // ... };  template<typename ...T> void operator++(B, T...) {   std::cout << ((sizeof...(T) == 0) ? "prefix" : "postfix") << std::endl; }  int main() {   B b;   b++;   ++b; } 

GCC compiles and works fine with this, but clang says

main.cpp:9:24: error: parameter of overloaded post-increment operator must have type 'int' (not 'T...')

void operator++(B, T...) { 

Who is right?


Thanks to anyone who helped me understand GCC's behavior. I filed a new Clang bug report:

http://llvm.org/bugs/show_bug.cgi?id=14995

like image 279
Johannes Schaub - litb Avatar asked Jan 16 '13 23:01

Johannes Schaub - litb


People also ask

What type of operator uses postfix and prefix?

Increment ++ and Decrement -- Operator as Prefix and Postfix In programming (Java, C, C++, JavaScript etc.), the increment operator ++ increases the value of a variable by 1. Similarly, the decrement operator -- decreases the value of a variable by 1. Simple enough till now.

Is ++ i ++ valid in C?

++i++ is an error by the current definition of C. The language could easily be changed to have an explicit rule for this expression (produce the value ((i+=2),i-1) ), but given how often it would be used, it's hardly worth the effort.

How does the compiler differentiate between a prefix operator and a postfix operator?

The main difference between prefix and postfix is that the prefix is a notation that writes the operator before operands while the postfix is a notation that writes the operator after the operands.

How will you distinguish between postfix and prefix operators in overloading?

To distinguish between the two, the following rule is observed: The prefix form of the operator is declared exactly the same way as any other unary operator; the postfix form accepts an extra argument of type int .


1 Answers

ORIGINAL ANSWER: (not deleted as it may contain useful information)

I would say it all boils down to whether an overloaded operator template is considered to be an overloaded operator or not. Logically, I would like to think this is not the case, and Clang is wrong: I believe the template should be first selected as a candidate for overload resolution based on name and signature compatibility, then instantiated, then (possibly) selected. The way I see it, only after instantiation the compiler should check whether the resulting function has the proper amount of arguments or not.

But that is only my opinion. Per § 13.5.7/1 about overloading of the postfix operator ++:

"If the function is a member function with one parameter (which shall be of type int) or a non-member function with two parameters (the second of which shall be of type int), it defines the postfix increment operator ++ for objects of that type"

The Standard does not seem to clarify whether a function template shall be considered as a function for what concerns the restrictions on the signature of legal operator overloads (at least, I could not find any sentence that solves this ambiguity). As long as this is true, this question can hardly be given a clear answer, and we are left with opinions.

But I would like to mention another relevant aspect of the matter: consistency.

Although it is true that the code in the question's text does not compile on Clang, the following does:

template<typename... Ts> int operator + (X x1, Ts... args) {     return 0; } 

I do not see any conceptual difference between the two cases: if the signature of the operator overload is to be checked before instantiation, then the above definition should not compile either. If this is not the case, then the code in the question's text should compile.

So the answer in my opinion is that either GCC is right, or they are both wrong.

UPDATE:

As @JesseGood and @SethCarnegie correctly point out, per 14.7/4:

"A specialization is a class, function, or class member that is either instantiated or explicitly specialized."

Moreover, per 14.6/8:

"No diagnostic shall be issued for a template for which a valid specialization can be generated."

Thus, it seems Clang is indeed wrong and no compilation error shall be produced for the operator function template in the question's text.

like image 53
Andy Prowl Avatar answered Sep 20 '22 05:09

Andy Prowl