0

I have two classes: CoolEnum, which is an attempt to turn enum class into a real class with methods; template <class WrapMe> class Wrapper;, which is implicitly convertible to const WrapMe&

I've come up with the following implementation:

#include <cassert>

class CoolEnum {
public:
    enum Impl {
        kFirst, kSecond
    };

    explicit CoolEnum(Impl value) : value_(value) {
    }

    operator Impl() const {
        return value_;
    }

    CoolEnum Inverse() const {
        switch (value_) {
            case kFirst:
                return CoolEnum{kSecond};
            default:
                return CoolEnum{kFirst};
        }
    }

private:
    Impl value_;
};

template <class WrapMe>
class Wrapper {
public:
    Wrapper(WrapMe value, char other_info)
        : value_(value), other_info_(other_info) {
    }

    operator const WrapMe&() const {
        return value_;
    }

private:
    WrapMe value_;
    char other_info_;
};

int main() {
    // compiles
    assert(CoolEnum(CoolEnum::kFirst) == CoolEnum::kFirst);

    // does not compile: no match for operator ==
    assert(CoolEnum(CoolEnum::kFirst)
       == Wrapper<CoolEnum>(CoolEnum(CoolEnum::kFirst), 'e'));
    return 0;
}

I surely can just static_cast Wrapper<CoolEnum> to CoolEnum, but I believe that it might be possible to fix CoolEnum class and avoid it.

One of the solutions I know of is to remove operator Impl from CoolEnum, and I guess its because it results in ambiguity (though I don't fully understand why). To elaborate, I believe there are several possibilities for operator ==:

  1. convert Wrapper to CoolEnum and compare

  2. convert Wrapper to Impl and compare

  3. ... (maybe others)

but it seems like it should trivially be allowed -- all of them are compiler-generated, and lead to the same result

I have two questions:

  1. Why exactly do I get a compilation error?

  2. What is the best possible fix for CoolEnum class?

Thanks!

1
  • Where is the operator== definition? Commented Jul 8, 2019 at 16:28

1 Answer 1

2

Why exactly do I get a compilation error?

You are only allowed one user defined conversion in a conversion sequence. When you do

CoolEnum(CoolEnum::kFirst) == Wrapper<CoolEnum>(CoolEnum(CoolEnum::kFirst)

CoolEnum(CoolEnum::kFirst) can be converted to a CoolEnum::Impl in a single step but Wrapper<CoolEnum>(CoolEnum(CoolEnum::kFirst) first has to convert the Wrapper to a CoolEnum, and then convert that to a CoolEnum::Impl. Since that is two user defined conversions you get an error

What is the best possible fix for CoolEnum class?

Just add a operator == for it. You can then do the comparison of the enum value in there. This will work because it only take a single user defined conversion to go from a Wrapper<T> to T. Changing the code to

#include <cassert>

class CoolEnum {
public:
    enum Impl {
        kFirst, kSecond
    };

    explicit CoolEnum(Impl value) : value_(value) {
    }

    operator Impl() const {
        return value_;
    }

    CoolEnum Inverse() const {
        switch (value_) {
            case kFirst:
                return CoolEnum{kSecond};
            default:
                return CoolEnum{kFirst};
        }
    }
    friend bool operator ==(const CoolEnum& lhs, const CoolEnum& rhs);
    // ^^^^^^^^^^^^^^^^^ added this ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

private:
    Impl value_;
};

bool operator ==(const CoolEnum& lhs, const CoolEnum& rhs)
{
    return lhs.value_ == rhs.value_;
}
// ^^^^^^^^^^^^^^^^^ added this ^^^^^^^^^^^^^^^^^^^^^^^^^^

template <class WrapMe>
class Wrapper {
public:
    Wrapper(WrapMe value, char other_info)
        : value_(value), other_info_(other_info) {
    }

    operator const WrapMe&() const {
        return value_;
    }

private:
    WrapMe value_;
    char other_info_;
};

int main() {
    // compiles
    assert(CoolEnum(CoolEnum::kFirst) == CoolEnum::kFirst);

    // does not compile: no match for operator ==
    assert(CoolEnum(CoolEnum::kFirst)
       == Wrapper<CoolEnum>(CoolEnum(CoolEnum::kFirst), 'e'));
    return 0;
}

lets it compile

Sign up to request clarification or add additional context in comments.

1 Comment

"You are only allowed one user defined conversion in a conversion sequence" Thanks for clarifying! That's exactly the answer I was looking for

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.