4

It seems that in c++ in purely boolean context, operator char*() has higher precedence than operator bool() const; and enabling c++11 mode and using explicit operator bool() const doesn't help. Is this a bug in g++ or a misfeature in the language standard? Or is there a good reason for this crazy behavior that I am not seeing?

A simple demonstration of the issue:

#include <stdio.h>

struct A
{
    char buf[512];
    int err;

    operator char* () { return buf; }
    operator const char* () const { return buf; }
    operator bool () const { return !err; }
    // explicit operator bool () const { return !err; } // same problem
};

int main()
{
    A a;
    a.err = -42;
    if (a) {
        printf("lolwut?\n");
        return 1;
    }
    return 0;
}
tetromino
  • 3,490
  • 1
  • 15
  • 8
  • 1
    It is probably due to the `const`. Did you try adding `operator bool() { return !err}`? – juanchopanza Apr 29 '14 at 05:51
  • Yes, adding a non-const version of `operator bool()` is a solution, but it feels like ugly and unnecessary code duplication (especially since in my real code, the check is not quite as simple as `!err`:) – tetromino Apr 29 '14 at 05:54
  • There are ways to avoid code duplication between `const` and non-`const` methods. – juanchopanza Apr 29 '14 at 05:55
  • found duplicate http://stackoverflow.com/questions/22064519/why-doesnt-explicit-bool-conversion-happen-in-contextual-conversion?rq=1 – bolov Apr 29 '14 at 05:57
  • The problem is ages old: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool. If you can use c++11, consider using `explicit operator bool`. – oakad Apr 29 '14 at 05:57
  • @oakad, no, `explicit operator bool () const` doesn't help. – tetromino Apr 29 '14 at 05:59
  • 3
    What about `explicit operator char`? You can make all conversions explicit, after all. – oakad Apr 29 '14 at 06:00

1 Answers1

1

As explained by @oakad — the elegant solution is to use explicit operator char*() in c++11 mode. This will ensure operator char*() simply doesn't get used in boolean context.

As explained by @bolov — the observed behavior is part of the language standard. According to 13.3.1, for the purpose of resolving overloaded functions, methods are considered to have an implicit object parameter. For methods declared without a ref-qualifier, this parameter is a reference to the class with the corresponding cv-qualifier.

So we effectively have the following situation:

char* op(A& a) { return a.buf; }
bool op(const A& a) { return !a.err; }

Since a was non-const in main(), the non-const operator gets picked. It doesn't matter whether we had operator char*() or operator int() or operator double() — a non-const cast operator which could be used in boolean context would have higher precedence than operator bool() const.

tetromino
  • 3,490
  • 1
  • 15
  • 8