将运算符类型转换为除某些引用之外的任何算术类型

Type cast operators to any arithmetic type except some reference

假设我们有这样一个例子class:

class Union {
    union Value {
        int i;
        float f;
    };
    enum class Type {
        Int, Float
    };
    Type type;
    Value value;

public:
    operator int&() { return value.i; }
    operator float&() { return value.f; }

    template <typename T, is_arithmetic<T>>
    operator T() const {
        if (type == Type::Int)
            return static_cast<T>(value.i);
        else
            return static_cast<T>(value.f);
    }
}

我想允许 Union 实例转换为任何算术类型,但禁止转换为引用,示例中的 int 和 float 类型除外。对于给定的示例,编译器通知存在多个转换。如何处理这样的问题?有可能吗?

问题是is_arithmetic<T>。它没有你想象的那样。那是一个模板非类型参数。 is_arithmetic是一个class,一个类型。

可以这样想:

template <class T, int N>
struct X {};

也可以省略参数名:

template <class T, int>
struct X {};

现在 int 变成了 is_arithmetic<T>.

摆脱它,它起作用了:

template <typename T>
operator T() const {

我的意见是,您无需确保 T 是算术类型,因为 static_cast 会为您做到这一点。

如果你想在声明中强制执行,你需要 SFINAE 和 enable_if,直到我们有了概念:

template <class T, class Enable = std::enable_if_t<std::is_arithmetic<T>::value>>
operator T() const {

我对你的设计也有一些担忧。根据经验,隐式转换是不好的。所以你至少可以让它们明确。

我想出了一个解决方案,比如实现给定的运算符:

operator int&();
operator float&();
operator T();
operator T() const;

使用这组运算符,我能够像我预期的那样定义算术变量,即非常量、常量、常量引用和特定类型(如 int 和 float)的额外引用。