Как я должен боксировать целочисленные типы в C ++? - PullRequest
0 голосов
/ 16 ноября 2018

Предположим, что в моем коде где-то есть

using foo = int32_t;

и

using bar = int32_t;

, тогда по какой-то причине мне нужно провести различие между этим типом и другими int32_t с (и ихпсевдонимы).Но - я все еще хочу, чтобы они вели себя так же, как int32_t s.

Теперь я могу написать:

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

, который различает типы.Но - эти структуры не ведут себя как int с вообще;Я даже не могу сравнить foo с друг с другом!(Ну, во всяком случае, до C ++ 20)

Поскольку int32_t не является классом, я не могу сделать:

struct foo : public int32_t { }

, хотя это будетдай мне именно то, что мне нужно.

Так что, похоже, я хочу добиться "упаковки" (а-ля Java, C # и т. Д.) Простых целых чисел в классы, а об остальном позаботится наследование.

Безусловно, можно вычеркнуть множество шаблонов и реализовать все соответствующие операторы для целых чисел: присваивание, сравнение, арифметика и т. Д. Но, вы знаете, DRY !

Если бы я мог переопределить оператор точка , это могло бы сэкономить мне весь код, но это предложение застряло и не похоже, что оно куда-нибудь скоро пойдет.

Так жеЕсть что-то еще, что я мог бы использовать, чтобы избежать всего этого шаблона?

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

Сильные typedefs

В нескольких комментариях на сайте и за его пределами (включая @HenriMenke) появился термин "сильный typedef".С ++ typedefs "слабые" - они определяют неразличимые псевдонимы.Сильная typedef нового типа T как типа U заставит T вести себя как U, но не будет иметь тип U.

То, что вы хотите сделать, это определить две "сильные определения типа" foo и bar как int.

Есть, по крайней мере, две распространенные библиотеки strong-typef, ну, я думаю, вы могли бы сказать:

0 голосов
/ 16 ноября 2018

Есть один способ, которым я пытался (но не сильно проверенный), чтобы избежать повторения шаблона.Он использует шаблоны, чтобы легко создать новый тип, просто указав другой номер в качестве параметра шаблона.Результирующий тип может быть псевдонимом типа, чтобы избавиться от уродливого определения шаблона:

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';
}

Вы создаете шаблон один раз как шаблон класса и создать экземпляр как различные типы , просто указав уникальный индекс в качестве первого параметра шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...