Предположим, мой код имеет
using foo = int32_t;
где-то и
using bar = int32_t;
тогда по какой-то причине мне нужно различать этот тип и другие int32_t
s (и их псевдонимы). Но — я все еще хочу, чтобы они вели себя так же, как 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!
Если бы я мог переопределить точку оператора, это могло бы сэкономить мне весь код, но это предложение застряло и не похоже, что оно куда-нибудь пойдет в ближайшее время.
Так есть ли что-то еще, что я мог бы использовать, чтобы избежать всего этого шаблона?
Есть один способ, которым я пытался (но не тщательно проверял), чтобы избежать повторения шаблона. Он использует шаблоны, чтобы легко создать новый тип, просто указав другой номер в качестве параметра шаблона. Результирующий тип может быть псевдонимом типа, чтобы избавиться от уродливого определения шаблона:
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';
}
Вы создаете шаблон один раз как шаблон класса а также иллюстрировать примерами это как разные типы просто поставляя уникальный индекс в качестве первого параметра шаблона.
Несколько комментариев на сайте и вне его (в том числе @HenriMenke) подняли термин «сильный typedef». С ++ typedefs «слабые» — они определяют неразличимые псевдонимы. Сильная typedef нового типа T как типа U заставит T вести себя как U, не имея типа U.
То, что вы хотите сделать, это определить две «сильные определения типа» foo
и из bar
как инт.
Есть, по крайней мере, две распространенные библиотеки strong-typedef, ну, я думаю, вы могли бы сказать:
type_safe
(репо на GitHub): Обеспечивает ts::integer<T>
strong typdef
, который старше и на основе макросов