解决隐藏歧义的不明确用户定义转换

Resolving ambiguous user-defined-conversion where ambiguity is hidden

本文关键字:用户 定义 转换 不明确 隐藏 歧义 解决      更新时间:2023-10-16

下面的代码为整数创建一个基类包装器。它提供了一个方法来获取和设置其值,以及一个用户定义的转换和一个赋值运算符,以方便使用。

派生类是一个模板(旨在与枚举一起使用),它继承了基类包装器,

该包装器隐藏了基类的值(),用户定义的转换和赋值运算符,并将它们替换为专门与提供的模板参数(枚举)一起使用的版本。

class Base
{
public:
    Base( int e ) : e_(e) {}
    inline const int& value() const { return e_; }
    inline void value( int e ) { e_ = e; }
    inline operator const int& () const { return value(); }
    inline Base& operator= ( int e ) { value( e ); return *this; }
protected:
    int e_;
};
template< typename E >
class Enum : public Base
{
    using Base::value;
    using Base::operator const int&;
    using Base::operator=;
public:
    Enum( E e ) : Base( e ) {}
    inline E value() const { return static_cast<E>( Base::value() ); }
    inline void value( E e ) { Base::value( e ); }
    inline operator E () const { return static_cast<E>( Base::value() ); }
    inline Enum<E>& operator= ( E e ) { Base::value( e ); return *this; }
};
enum foo_t {
    FOO_A,
    FOO_B,
    FOO_C
};
typedef Enum<foo_t> Foo;

现在让我们像这样调用这段代码:

Foo e( FOO_A );
e = FOO_B; // Ok!
foo_t b = e; // Ok!
// Why is this not ok?
if ( e ) {
    printf("error C2451!");
}
if ( e.value() ) { // Ok!
    e = FOO_C;
}
// Why is this not ok?
switch ( e ) {
default:
    printf("error C2450!");
}
switch ( e.value() ) { // Ok!
default:
    e = FOO_A;
}

为什么当我显式隐藏基类的用户定义转换时,if 和 switch 语句无法编译 ( Ambiguous user-defined-conversion )(并且 if 和 switch 语句应该无法访问)。同样模棱两可的e.value()函数不会受到此问题的影响。

1>test.cpp(60): error C2451: conditional expression of type 'Foo' is illegal
1>          Ambiguous user-defined-conversion
1>test.cpp(69): error C2450: switch expression of type 'Foo' is illegal
1>          Ambiguous user-defined-conversion

ref#1 和 ref#2 (我似乎找不到实际说这句话的标准,只有人们引用它......

看来C++标准对条件有这样的说法:

条件应为整型、枚举型或

存在单个非显式转换为整型或枚举类型的类类型 (12.3)。如果条件是类类型,则通过调用该转换函数来转换条件,并且在本节的其余部分中使用转换结果代替原始条件。进行整体促销。

由于有 2 个用户定义的转换"可用",即使只有 1 个可以访问,标准也说这不行。

(这些using语句在Enum是什么? 我不知道他们是做什么的。

我不确定为什么会发生错误,但是您当然可以通过向Base添加以下内容来解决if语句的问题:

inline operator bool () const { return e_ != 0; }

至于switch,我从未见过除了允许的整数类型之外的任何东西(Foo不是),我怀疑编译器是否足够聪明,可以尝试自己找到强制转换为枚举运算符。 无论如何,我总是会在那里打电话给value()