解决隐藏模糊性的模糊用户定义转换

时间:2014-02-13 01:28:26

标签: c++

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

派生类是一个模板(旨在与枚举一起使用),它继承Base类包装器,它隐藏Base类的value(),用户定义转换和赋值运算符,并将它们替换为专门用于它的版本。提供的模板参数(枚举)。

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语句在我明确隐藏基类'用户定义转换(而且if和switch语句不可访问)时无法编译(Ambiguous user-defined-conversion)。同样含糊不清的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

2 个答案:

答案 0 :(得分:1)

ref#1ref#2(我似乎无法找到标准实际说这个,只有人引用它......)

似乎C ++标准有关于条件的说法:

  

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

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

答案 1 :(得分:-1)

using中的这些Enum陈述是什么?我不知道他们做了什么。)

我不确定错误发生的原因,但您可以通过向if添加类似的内容来解决Base语句的问题:

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

至于switch,我从来没有见过任何东西,只允许整数类型(Foo不是),我怀疑编译器是否足够聪明,试图找到转换为枚举运算符本身。无论如何我总是打电话给value()