简体   繁体   English

隐式用户定义的转换很麻烦

[英]Trouble with implicit user-defined conversions

I have two classes: CoolEnum , which is an attempt to turn enum class into a real class with methods; 我有两个类: CoolEnum ,它试图通过方法将enum class变成真实的类; template <class WrapMe> class Wrapper; , which is implicitly convertible to const WrapMe& ,可以隐式转换为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. 我当然可以只static_cast Wrapper<CoolEnum>CoolEnum ,但是我相信可以修复CoolEnum类并避免它。

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). 我知道的解决方案之一是从CoolEnum删除operator Impl ,我猜是因为这会导致歧义(尽管我不完全理解为什么)。 To elaborate, I believe there are several possibilities for operator == : 详细地说,我相信operator ==有几种可能性:

  1. convert Wrapper to CoolEnum and compare Wrapper转换为CoolEnum并进行比较

  2. convert Wrapper to Impl and compare Wrapper转换为Impl并进行比较

  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? CoolEnum类的最佳解决方案是CoolEnum

Thanks! 谢谢!

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 CoolEnum(CoolEnum::kFirst)可以一步转换为CoolEnum::Impl ,但是Wrapper<CoolEnum>(CoolEnum(CoolEnum::kFirst)首先必须将Wrapper转换为CoolEnum ,然后再将其转换为CoolEnum::Impl ,因为这是两个用户定义的转换,所以会出现错误

What is the best possible fix for CoolEnum class? CoolEnum类的最佳解决方案是什么?

Just add a operator == for it. 只需为其添加一个operator == 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 . 这将起作用,因为仅需一次用户定义的转换即可将Wrapper<T>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 让它编译

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM