Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

operator>>(,) overload behaving in a surprising way

Well, maybe it is not so surprising. Stackoverflow has a lot of questions and contributions to that point. Only they are not EXACTLY to the point.

Here an extract from the C++ standard (in fact a c++14 draft, but I assume the passage is the same in current C++11 standard):

An operator function shall either be a non-static member function or be a non-member function that has at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration. It is not possible to change the precedence, grouping, or number of operands of operators. The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator functions that implement these operators. Operator functions are inherited in the same manner as other base class functions.

Thus, to my understanding, it is perfectly legal to have 1 class type and one non-class type as parameters to operator>>(,). The standard does not say "The first" or "The second" parameter. Just "One" of them must be a class type.

Here a code snippet which surprises me:

int operator>> ( int v, std::function<int(int)> transformer )
{
    int v1 = transformer(v);
    DGS::CLogger::GetLogger()->Log<int>(&IntFormatter, v1 );
    return v1;
}
static int DoItLoggedAndCompact( int value )
{
    int x = operator>>( operator>>(value, DoIt) , AnotherIntCalculation ); // compiles and works!
    return x;
// The following line produces (with clang++):
// error: invalid operands to binary expression ('int' and 'int (*)(int)')
//      return value >> DoIt >> AnotherIntCalculation; : 
}

Please note that "A function pointer is not a class type", while being a correct statement, is not a comprehensive answer. As you see in the rewritten code starting with int x = ... and the definition of operator>> second parameter, the function pointer is silently converted to a std::function.

I cannot find anywhere in the standard a passage which states, that the conversion rules for those two (allegedly) synonymous forms differ.

So, is this a compiler bug, a community wide over-interpretation of the C++ specification or...something else we see here? Or simply some stupid oversight on my part?

like image 397
BitTickler Avatar asked Jan 07 '15 19:01

BitTickler


1 Answers

But "A function pointer is not a class type" is the correct answer.

There's the following note in clause 13.6:

operator overload resolution occurs only when an operand expression originally has class or enumeration type

The normative rule is in 13.3.1.2 (emphasis mine):

If no operand of an operator in an expression has a type that is a class or an enumeration, the operator is assumed to be a built-in operator and interpreted according to Clause 5.

If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table 11.

The forms are synonymous only when one of the operands is a class type. Since neither one is here, the rewrite as operator>>() doesn't occur.

like image 60
Ben Voigt Avatar answered Sep 20 '22 01:09

Ben Voigt