【问题标题】:Type cast operators to any arithmetic type except some reference类型转换运算符到除某些引用之外的任何算术类型
【发布时间】:2016-03-29 16:31:58
【问题描述】:

假设我们有这样一个示例类:

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 类型。对于给定的示例,编译器会通知存在多个转换。如何处理这样的问题?有没有可能?

【问题讨论】:

    标签: c++ casting operator-overloading


    【解决方案1】:

    问题是is_arithmetic&lt;T&gt;。它不像你认为的那样。那是一个模板非类型参数。 is_arithmetic 是一个类,一个类型。

    这样想:

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

    而且你也可以省略参数名:

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

    现在你有is_arithmetic&lt;T&gt;,而不是int

    摆脱它,它就起作用了:

    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 {
    

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

    【讨论】:

    • 我写 is_arithmetic 的方式更像是伪代码,不会用不必要的代码使示例变得臃肿。我将提出我在答案中提出的解决方案。
    • 不过,我感谢您对模板的解释。
    【解决方案2】:

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

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

    使用这组运算符,我可以定义我所期望的算术变量,即非常量、常量、常量引用以及特定类型(如 int 和 float)的额外引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 2014-10-01
      • 1970-01-01
      相关资源
      最近更新 更多