Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User-defined implicit conversion of an enum class when calling an overloaded operator fails

Consider the following example:

struct ConvertibleStruct {};

enum class ConvertibleEC {};

struct Target {
    // Implicit conversion constructors
    Target(ConvertibleStruct) {}
    Target(ConvertibleEC) {}
};

Target operator~(const Target& t) {
    return t;
}

Target anotherFunction(const Target& t) {
    return t;
}

int main() {
    ConvertibleStruct t;
    ConvertibleEC ec;

    ~t;                   // 1. Works finding the operator overloaded above
    ~ec;                  // 2. Fails to compile on clang 3.4 and gcc 4.8.2
    operator~(ec);        // 3. Works finding the operator overloaded above

    anotherFunction(ec);  // 4. Works
}

Compiler versions:

The above findings are for clang 3.4 and gcc 4.8.2. Test 2. actually compiles fine on gcc 4.7.3 with -std=c++11. Possibly a bug in early GCC C++11 implementation?

Assertions:

  • Given that 1. compiles, user-defined implicit-conversions are checked when calling the ~ operator.
  • Given that 4. compiles, user-defined implicit-conversions are checked for enum class objects.

Questions:

  • Are the above assertions correct?
  • If they are, why does 2. fail to compile?
  • Given that 2. fails to compile, why does 3. compile?
like image 854
Clivest Avatar asked Sep 29 '22 07:09

Clivest


1 Answers

The second test, ~ec runs into a peculiarity of the name lookup for operators in expressions: [over.match.oper]/3 (from the "ancient" N3797):

For a unary operator @ with an operand of a type whose cv-unqualified version is T1 [...]

The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls except that all member functions are ignored. However, if no operand has a class type, only those non-member functions in the lookup set that have a first parameter of type T1 or “reference to (possibly cv-qualified) T1”, when T1 is an enumeration type [...] are candidate functions.

So the ::operator~(const Target&) should not be found/used with a for an expression with a unary operator applied to an operand of type ConvertibleEC.


For the first, ~t, the operand is of class type and the above exception does not apply.

Both the third and the fourth test do not use operator lookup, but usual unqualified lookup. The usual unqualified lookup finds ::operator~(const Target&) (in cases 1 and 3) and anotherFunction (in case 4).

like image 103
dyp Avatar answered Oct 09 '22 01:10

dyp