1

I have a header file that defines a class with a boolean_type conversion operator in it, which is used in main.cpp. I am not able to understand how the boolean_type operator is getting called in an if statement

Header.h

template <typename Type>
class Sptr
{
public:
    struct boolean_struct { int member; };
    typedef int boolean_struct::* boolean_type;

    operator boolean_type() const throw()
    {
        return nullptr != m_value ? &boolean_struct::member : nullptr;
    }

    explicit Sptr(Type value = nullptr) throw() :
        m_value(value)
    {
    }

private:
    Type m_value;
};

main.cpp

int main()
{
    int* p = new int;
    Sptr<int*> sPtr(p);
    if (sPtr) //>>>>> How this is calling operator boolean_type() ?
    {
        std::cout << "hellos";
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Tom
  • 13
  • 4

1 Answers1

1

C++ is all to happy to make a construct work, so long as it can (within certain constraints) find a valid conversion sequence to types that work in the given context.

In this case, the compiler sees an if statement, which expects an operator of type bool. It will therefore attempt to form a bool value from sPtr. A conversion sequence can be formed from at most one user-defined conversion, but may contain more standard conversions.

In this case, the first conversion in the sequence is the user defined one to boolean_type. Following that, we can perform the following standard conversion

[conv.bool] (emphasis mine)

1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer-to-member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.

boolean_type is a pointer-to-member type. And so can be converted to the bool we need for the if statement to work.

The reason such code may have been written in the past, is in the first paragraph to this answer. C++ can be too conversion happy. Had the user-defined conversion been a plain operator bool, one could end up with silliness such as this

sPtr * 2; // What is multiplying a pointer even mean!? Why?
foo(sPtr); // But foo expects an int!

The conversion to bool permits using sPtr in contexts that require an integral type, because, as it were, bool is also an integral type in the C++ type system! We don't want that. So the above trick is employed to prevent the compiler from considering our user-defined conversion in more contexts than we want.

Nowadays, such tricks are not required. Since C++11, we have the notion of type being contextually converted and explicit conversion operators. Basically if we write instead

explicit operator bool()

This operator will only be called in very specific contexts (such as the condition in an if statement), but not implicitly in the problematic examples listed above.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458