首页 > 解决方案 > 我应该如何在 C++ 中装箱整数类型?

问题描述

假设我的代码有

using foo = int32_t;

某处,和

using bar = int32_t;

然后,出于某种原因,我需要区分这种类型和其他int32_ts(及其别名)。但是 - 我仍然希望他们表现得像int32_ts。

现在,我可以写:

struct foo { int32_t value; }
struct bar { int32_t value; }

区分类型。但是 - 这些结构的行为根本不像 ints;我什foo至不能互相比较!(好吧,无论如何都不会在 C++20 之前)

由于int32_t不是一堂课,我不能这样做:

struct foo : public int32_t { }

虽然这会给我我所需要的。

因此,似乎我想要实现的是将普通整数“装箱”(a-la Java、C# 等)到类中,其余的将通过继承来处理。

当然可以脱口而出大量样板文件并实现整数的所有相关运算符:赋值、比较、算术等。但是,你知道,DRY

如果我可以覆盖 operator dot,那可以节省我所有的代码,但是该提案被卡住了,看起来它不会很快到达某个地方。

那么还有什么我可以利用的东西来避免所有这些样板吗?

标签: c++integerclass-designidioms

解决方案


我尝试了一种方法(但没有经过大量测试)来避免重复样板。它使用模板轻松地通过提供不同的数字作为模板参数来创建新类型。生成的类型可以是类型别名以摆脱丑陋的模板定义:

namespace alt {

template<std::size_t TypeId, typename Number>
class typed_number
{
public:
    explicit typed_number(Number n): n(n) {}
    typed_number(typed_number const& tn): n(tn.n) {}

    typed_number& operator= (typed_number const& tn) { this->n  = tn.n; return *this; }
    typed_number& operator+=(typed_number const& tn) { this->n += tn.n; return *this; }
    typed_number& operator-=(typed_number const& tn) { this->n -= tn.n; return *this; }
    typed_number& operator*=(typed_number const& tn) { this->n *= tn.n; return *this; }
    typed_number& operator/=(typed_number const& tn) { this->n /= tn.n; return *this; }

    explicit operator Number() const { return n; }

    bool operator==(typed_number tn) const { return this->n == tn; }
    bool operator!=(typed_number tn) const { return this->n != tn; }
    bool operator<=(typed_number tn) const { return this->n <= tn; }
    bool operator>=(typed_number tn) const { return this->n >= tn; }
    bool operator< (typed_number tn) const { return this->n <  tn; }
    bool operator> (typed_number tn) const { return this->n >  tn; }

    typed_number operator+(typed_number const& tn) const { return typed_number(this->n + tn.n); }
    typed_number operator-(typed_number const& tn) const { return typed_number(this->n - tn.n); }
    typed_number operator*(typed_number const& tn) const { return typed_number(this->n * tn.n); }
    typed_number operator/(typed_number const& tn) const { return typed_number(this->n / tn.n); }

    friend std::ostream& operator<<(std::ostream& os, typed_number<TypeId, Number> n)
        { return os << n.n; }

    friend std::istream& operator>>(std::istream& is, typed_number<TypeId, Number>& n)
        { return is >> n.n; }

private:
    Number n;
};

}  // namespace alt

// give each incompatible type a different index
using dollars = alt::typed_number<0, int>;
using cents = alt::typed_number<1, int>;

int main()
{
    auto d1 = dollars(5);
    auto d2 = dollars(9);

    auto d3 = d1 + d2;

    std::cout << d1 << " + " << d2 << " = " << d3 << '\n';
}

您将样板作为模板类创建一次,然后仅通过提供唯一索引作为第一个模板参数将其实例化为不同的类型。


推荐阅读