Question

I found something I consider strange behaviour in C++: a typecast operator in a private base class is confusing the compiler when trying to resolve an implicit cast:

#include <iostream>
struct Base
{
#ifdef ENABLE
    operator bool () const { return true; }
#endif
};
struct Derived : private Base
{
    operator int () const { return 7; }
};
int main()
{
    Derived o;
    std::cout << o << '\n';
    return 0;
}

Without -DENABLE, the code compiles just fine, and outputs 7. With -DENABLE, the code no longer compiles, complaining about an ambiguous overload. I tried gcc-4.6.5, gcc-4.8.1, and clang-3.3. What's confusing is that I clearly cannot ask for (bool)o, because Base is a private base.

Is this expected behaviour?

Was it helpful?

Solution

Access control always comes last. Quote from the Standard:

10.2 Member name lookup [class.member.lookup]

1 Member name lookup determines the meaning of a name (id-expression) in a class scope (3.3.7). Name lookup can result in an ambiguity, in which case the program is ill-formed. For an id-expression, name lookup begins in the class scope of this; for a qualified-id, name lookup begins in the scope of the nestedname- specifier. Name lookup takes place before access control (3.4, Clause 11).

8 If the name of an overloaded function is unambiguously found, overloading resolution (13.3) also takes place before access control. Ambiguities can often be resolved by qualifying a name with its class name.

The reason both operators are considered is that a) the base clas conversion is not hidden by the derived one (which it would if both had been converting to the same type), b) both bool and int can be written to stdout, c) neither is a better match than the other so overload resolution yields an ambiguity. This yields a hard error even before access control comes into play.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top