Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When overloading operators in C++ why is T* preferred over bool?

I have a wrapper class that should behave like a pointer. I have overloaded operator T* and operator bool. Bool does some extra validation. I tried using the object inside an if, but I notice that operator T* is called and not bool. Can someone explain me why? Is this somehow specified in the standard? I tested the sample code below in MSVC, clang and gcc and they all call operator T*. Also, from what I read on this page(https://en.cppreference.com/w/cpp/language/implicit_conversion), the if should try to cast to bool.

#include <stdio.h>

class MyClass
{
public:
    MyClass(int i)
        : m(i)
    {}

    operator bool() const
    {
        printf("operator bool()\n");
        return m;
    }

    operator int* ()
    {
        printf("operator int* ()\n");
        return &m;
    }

private:
    int m;
};

int main()
{
    MyClass a(5);
    MyClass b(0);

    if (a)
        printf("a is true\n");
    else
        printf("a is false\n");

    if (b)
        printf("b is true\n");
    else
        printf("b is false\n");

    return 0;
}

PS: I also tried with !! and (bool), but it still calls operator int*(). For operator bool(), I have to call it explicitly.

like image 784
Radu C Avatar asked Nov 07 '19 11:11

Radu C


People also ask

Can we overload == operator?

Overloading Binary Operators Suppose that we wish to overload the binary operator == to compare two Point objects. We could do it as a member function or non-member function. To overload as a member function, the declaration is as follows: class Point { public: bool operator==(const Point & rhs) const; // p1.

Why is operator overloading useful?

Operator overloading is one of the best features of C++. By overloading the operators, we can give additional meaning to the operators like +-*/=.,= etc., which by default are supposed to work only on standard data types like int, float, char, void etc. It is an essential concept in C++.

Can you overload the operator for data type int?

No we cannot overload integer or float types because overloading means to change the working of existing operators or make them to work with objects int is single member not an object.

Which operator is overloaded for account object?

The = and & C++ operators are overloaded by default. For example, you can copy the objects of the same Class directly using the = operator. Operator precedence doesn't change the associatively and precedence of operators.


2 Answers

In your class definition the conversion operator operator bool is declared with the qualifier const but the objects used in the if statements are not constant objects.

operator bool() const
                ^^^^^
{
    printf("operator bool()\n");
    return m;
}

Remove the qualifier const and the operator operator bool will be called.

Or declare the conversion operator operator int * like

operator const int* () const
{
    printf("operator int* ()\n");
    return &m;
}

and again the operator operator bool will be called.

When an operator has the qualifier const and applied to a non-constant object then one more conversion that is the qualification conversion is required.

Moreover you may declare the operator even as explicit. For example

explicit operator bool() 
{
    printf("operator bool()\n");
    return m;
}
like image 91
Vlad from Moscow Avatar answered Oct 23 '22 04:10

Vlad from Moscow


If you want to see how to arrive at Vlad's (correct) answer yourself, the process is roughly

  1. if statement

    The condition is an expression which is contextually convertible to bool

  2. Contextual conversions come under Implicit conversions - note in particular that

    If there are multiple overloads of the function or operator being called, after the implicit conversion sequence is built from T1 to each available T2, overload resolution rules decide which overload is compiled.

    And then under Order of the conversions, that the third step "zero or one standard conversion sequence" comes after the user-defined conversion, and that this step can convert pointer to bool.

    This means that both the user-defined conversion operators are viable for the middle step in that sequence. Finally,

  3. Overload resolution

    describes how to select the best viable function. Since both operators are viable within the context of the middle step of the conversion sequence, the extra pointer-to-bool conversion that happens after this doesn't contribute to the overload ranking.

    Specifically, the ranking is based on the fact that one operator requires const qualification of its implicit first (this) parameter, and the other doesn't. This is why a pair of const- and non-const-qualified overloads of the same operator will always choose the overload whose qualification most closely matches the object it's being called on.

like image 44
Useless Avatar answered Oct 23 '22 03:10

Useless