svv
svv

Reputation: 446

Safe bool multiple conversions ambiguity

I have to implement safe bool idiom in order to support compilers that do not have explicit keyword (MSVC 2012 for example). The class that should be checkable for bool is modelling a pointer to many classes and therefore it should be convertible to these pointers. The following code illustrates the idea:

// Uncomment this line to change implementation to 'safe bool'
// #define _COMPILER_NO_EXPLICIT

#if !defined(_COMPILER_NO_EXPLICIT)
#define OPERATOR_BOOL_MYTYPE(...)
#define OPERATOR_BOOL_IMPLEMENTATION(...) \
    public: \
            explicit operator bool() const noexcept \
            { \
                    return __VA_ARGS__; \
            }
#else
#define OPERATOR_BOOL_MYTYPE(...) \
    private: \
            void safe_bool() {}; \
            typedef __VA_ARGS__ safe_bool_my_type_t; \
            typedef void (safe_bool_my_type_t::*safe_bool_t)()

#define OPERATOR_BOOL_IMPLEMENTATION(...) \
    public: \
            operator safe_bool_t() const noexcept \
            { \
                    return __VA_ARGS__ ? \
                            &safe_bool_my_type_t::safe_bool : \
                            nullptr; \
            }
#endif


class Convertible
{
public:
    operator int*() const
    { return nullptr; }

    operator double*() const
    { return nullptr; }

    OPERATOR_BOOL_MYTYPE(Convertible);
    OPERATOR_BOOL_IMPLEMENTATION(false);
};


int main(void)
{
    Convertible a;
    if (a)
    {
        // this 'if' statement introduces compilation error
        // in 'safe bool' implementation
    }
    return 0;
}

If we use explicit operator bool()-based implementation everything works fine. The problem is actually in ambiguous convertibility in "safe bool" based implementation. How should it be solved?

Note: Consider bool conversion implementation to be independent from other to-pointer conversion implementations. If it is not possible give me a clue how to implement it in dependent case e.g. if Convertible evaluates to true iff one of the other conversion operators are returning non null value.

UPD: I believe there is a way that makes one implicit conversion to be more preferable than all the other.

Upvotes: 0

Views: 113

Answers (2)

svv
svv

Reputation: 446

Actually there is no good solution. I've found one that partially meets my requirements and managed other requirements to be weaken.

According to http://en.cppreference.com/w/cpp/language/implicit_cast the set and order of implicit conversions is the following:

1) zero or one standard conversion sequence

2) zero or one user-defined conversion

3) zero or one standard conversion sequence

As both types of conversions from the question are user-defined and both allows further standard conversion to bool I've decided to change the operator int*() and operator double*() conversion functions to some other operator Ptr<int>() and operator Ptr<double> where Ptr<T> is a template class that behaves the same as a raw pointer does. Particularly it is convertible to bool but this doesn't matter as it is the second user conversion and therefore it is forbidden. So the only conversion to bool exists (which is from 'safe bool' implementation).

The drawback of this solution is that the clients code is required either to change interfaces or to perform explicit cast to raw pointer.

Upvotes: 0

John Zwinck
John Zwinck

Reputation: 249183

Are you sure you need to have implicit conversion to other pointer types? If you don't need that, the problem will go away.

And if you do need implicit conversion to a pointer type, the problem seems moot: you don't need to convert to bool, because converting to a pointer will also yield a value which can be truth-tested (just like a regular raw pointer).

But you are still left with the ambiguous conversion due to the fact that you have operators for both int* and double*. This part probably warrants a redesign, because it's not clear how you can expect to have a single value be implicitly convertible to multiple unrelated pointer types.

Upvotes: 1

Related Questions