在c++中包装算术类型

Wrapping arithmetic types in C++

本文关键字:类型 包装 c++      更新时间:2023-10-16

c++很棒,但是不能从算术类型继承,这有时是有用的。我写了以下内容:

template <typename type> class arithmetic
{
    static_assert(std :: is_arithmetic <type> :: value, "Please provide an arithmetic type.");
    // Members
    type _value;
public:
    // Constructors
    inline arithmetic() = default;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline arithmetic(const rtype &);
    // Arithmetic operators
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator + (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator - (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator * (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator / (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator % (const rtype &) const;
    inline auto operator + () const;
    inline auto operator - () const;
    inline auto operator ++ ();
    inline auto operator ++ (int);
    inline auto operator -- ();
    inline auto operator -- (int);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator = (const rtype &);
    // Comparison operators
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator == (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator != (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator > (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator < (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator >= (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator <= (const rtype &) const;
    // Logical operators
    inline auto operator ! () const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator && (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator || (const rtype &) const;
    // Bitwise operators
    inline auto operator ~ () const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator & (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator | (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator ^ (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator << (const rtype &) const;
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator >> (const rtype &) const;
    // Compound assignment operators
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator += (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator -= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator *= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator /= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator %= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator &= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator |= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator ^= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator <<= (const rtype &);
    template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type * = nullptr> inline auto operator >>= (const rtype &);
    // Member and pointer operators
    inline type * operator & ();
    inline const type * operator & () const;
    // Casting
    inline operator type & ();
    inline operator const type & () const;
};
// Constructors
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline arithmetic <type> :: arithmetic(const rtype & value) : _value(value)
{
}
// Arithmetic operators
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator + (const rtype & rvalue) const
{
    return this->_value + rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator - (const rtype & rvalue) const
{
    return this->_value - rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator * (const rtype & rvalue) const
{
    return this->_value * rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator / (const rtype & rvalue) const
{
    return this->_value / rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator % (const rtype & rvalue) const
{
    return this->_value % rvalue;
}
template <typename type> inline auto arithmetic <type> ::  operator + () const
{
    return +(this->_value);
}
template <typename type> inline auto arithmetic <type> ::  operator - () const
{
    return -(this->_value);
}
template <typename type> inline auto arithmetic <type> ::  operator ++ ()
{
    return ++(this->_value);
}
template <typename type> inline auto arithmetic <type> ::  operator ++ (int)
{
    return (this->_value)++;
}
template <typename type> inline auto arithmetic <type> ::  operator -- ()
{
    return --(this->_value);
}
template <typename type> inline auto arithmetic <type> ::  operator -- (int)
{
    return (this->_value)++;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator = (const rtype & rvalue)
{
    return this->_value = rvalue;
}
// Comparison operators
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator == (const rtype & rvalue) const
{
    return this->_value == rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator != (const rtype & rvalue) const
{
    return this->_value != rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator > (const rtype & rvalue) const
{
    return this->_value > rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator < (const rtype & rvalue) const
{
    return this->_value < rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator >= (const rtype & rvalue) const
{
    return this->_value >= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator <= (const rtype & rvalue) const
{
    return this->_value <= rvalue;
}
// Logical operators
template <typename type> inline auto arithmetic <type> ::  operator ! () const
{
    return !(this->_value);
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator && (const rtype & rvalue) const
{
    return this->_value && rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator || (const rtype & rvalue) const
{
    return this->_value || rvalue;
}
// Bitwise operators
template <typename type> inline auto arithmetic <type> ::  operator ~ () const
{
    return ~(this->_value);
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator & (const rtype & rvalue) const
{
    return this->_value & rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator | (const rtype & rvalue) const
{
    return this->_value | rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator ^ (const rtype & rvalue) const
{
    return this->_value ^ rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator << (const rtype & rvalue) const
{
    return this->_value << rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator >> (const rtype & rvalue) const
{
    return this->_value >> rvalue;
}
// Compound assignment operators
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator += (const rtype & rvalue)
{
    return this->_value += rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator -= (const rtype & rvalue)
{
    return this->_value -= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator *= (const rtype & rvalue)
{
    return this->_value *= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator /= (const rtype & rvalue)
{
    return this->_value /= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator %= (const rtype & rvalue)
{
    return this->_value %= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator &= (const rtype & rvalue)
{
    return this->_value &= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator |= (const rtype & rvalue)
{
    return this->_value |= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator ^= (const rtype & rvalue)
{
    return this->_value ^= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator <<= (const rtype & rvalue)
{
    return this->_value <<= rvalue;
}
template <typename type> template <typename rtype, typename std :: enable_if <__arithmetic :: __is_arithmetic_convertible <rtype> :: value> :: type *> inline auto arithmetic <type> ::  operator >>= (const rtype & rvalue)
{
    return this->_value >>= rvalue;
}
// Member and pointer operators
template <typename type> inline type * arithmetic <type> :: operator & ()
{
    return &(this->_value);
}
template <typename type> inline const type * arithmetic <type> :: operator & () const
{
    return &(this->_value);
}
// Casting
template <typename type> inline arithmetic <type> :: operator type & ()
{
    return this->_value;
}
template <typename type> inline arithmetic <type> :: operator const type & () const
{
    return this->_value;
}

它基本上只是算术类型的一个非常迂腐的包装。包装器有一个称为_value的算术成员,然后所有对任何运算符的调用都被转发到_value,并且有一个转换运算符到原始算术类型。

现在,我想知道,在某种情况下,比如,arithmetic <int>的行为会与int不同吗?我似乎什么也想不出来,但我想我应该问一个更有见地的意见。

另一方面,如果这如预期的那样工作并且arithmetic <int>的行为与int一样,那么为什么这不是标准的一部分?它看起来很容易实现,并且允许我们根据需要扩展算术类型。

一个问题——隐式转换序列中不超过一个用户定义的转换。考虑:

class C { C(int); };
void f(C);
f(42);  // works, calls f(C(42));
f(arithmetic<int>(42));  // wouldn't work.

另一个问题-模板专门化:

template <typename T> void f(T) { std::cout << "Generic"; }
template <> void f<int>(int) { std::cout << "Specialized"; }
f(42);  // calls specialized
f(arithmetic<int>(42));  // calls generic

离家更近-您可以使用arithmetic<int>但不能使用arithmetic<arithmetic<int>>。更一般地说,各种模板元编程技术将能够分辨出其中的区别。

任何明确期望使用int类型但提供了arithmetic<int>包装器的地方,都应该引起注意。定义隐式转换在某些情况下会有所帮助,但在涉及以下任何情况时就没有帮助了:

  • int引用。f(int&)不能接收arithmetic<int>&。同样,在这里,将对象转换为in将导致修改临时变量,而不是原始对象。f(int const&)的函数可以合理地期望表现良好,因为您应该期望函数不保留引用(但不能保证)。一般来说,如果将int型和对象视为不可变变量,则可以从隐式转换中获得更多好处。

  • int指针。出于同样的原因。int*不是arithmetic<int>*

  • int数组。在显式需要int[]的地方不能提供arithmetic<int>[]
  • int的任何模板类型。vector<arithmetic<int>>不能用于需要vector<int>的地方。
  • 不能提供F<arithmetic<int>>, F<T>F<int>有专门化,但不是一般情况你被阻止提供自己的专门化(嗯…这可能吗?例如,通过在.cxx中私有地定义所有已知的专门化。

同样,实例化F,其中F声明。如果您的类确实是算术类型,则还必须能够声明arithmetic<int>。在您的示例中:

static_assert(std :: is_arithmetic <type> :: value, "Please provide an arithmetic type.");

将导致它失败。