Этот вопрос мотивировано preferred mechanism to attach a type to a scalar?, но есть немного офф-трек с единицами-оф-меры ...Как создать тип, который ведет себя как другой тип?
Скажем, я хочу, чтобы создать Float
, который довольно много работ, как и float
(это не обязательно радикальный, в C# System.Float
составляет почти точно то же, что и float
, с той лишь разницей, что это имя типа, а другое - это ключевое слово).
Вы можете начать с простого struct Float final { float v; };
. И тогда, возможно, добавив кучу operator
перегрузок
inline auto operator+(Float lhs, Float rhs) {
return Float { lhs.v + rhs.v };
}
// ... and so on ...
inline bool operator<(Float lhs, Float rhs) {
return lhs.v < rhs.v;
}
// ... etc. ...
Теперь, мне нужно, чтобы иметь возможность конвертировать Float
в Double
struct Double final { double v; };
struct Float final { float v;
operator Double() const { return Double { v }; }
};
Теперь возможно добавить operator&()
, так что я могу легко взаимодействовать с устаревший код
extern void foo(const float*);
const Float f { 3.14 };
foo(&f);
вместо того, чтобы писать foo(&f.v)
.
И этот список можно продолжить ... Тогда, я понимаю, этот код одинаков для Float
и Double
, поэтому я использую шаблоны:
template<typename T>
struct Type final { T v; }
using Float = Type<float>;
using Double = Type<double>;
Но теперь я понимаю, что T
не может быть дешевым, чтобы скопировать как float
, так что я должен изменить свои перегруженные
template<typename T>
inline auto make_Type(T&& v) {
return Type<T> { std::forward<T>(v); }
}
template<typename T1, typename T2>
inline auto operator+(const Type<T1>& lhs, const Type<T2>& rhs) {
return make_Type(lhs.v + rhs.v);
}
И есть больше осложнений для произвольного T
; например, он может быть подвижным, но не копируемым.
Есть ли «канонический» способ сделать что-то подобное? Или это действительно начинает становиться (очень) грязным? Помогает ли это ограничить T
? (Мне действительно нужны только double
, int
и т. Д., А не std::string
или std::vector<T>
). Может быть, кто-то уже сделал это хорошо для (всего?) Всего?
Помните, что в конце концов я действительно хочу
template<typename T, typename Tag>
struct TaggedType final
{
typedef Tag tag_type;
typedef T value_type;
value_type value;
};
, но дело не с Tag
, кажется, хорошее упрощение (и избегает кроличью нору единиц).
Это здорово, выглядит быть * точно *, что я ищу! Он даже отвечает на мой вопрос выше: «Хотя вы можете имитировать их достаточно хорошо для встроенных типов, использование их для определенного пользователем типа очень многословно, поэтому на самом деле для них нужна собственная поддержка». –