2016-12-01 2 views
0

Этот вопрос мотивировано 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, кажется, хорошее упрощение (и избегает кроличью нору единиц).

ответ

1

Библиотека, которую вы ищете, недавно была размещена на сайте «Standard C++».

См Tutorial: Emulating strong/opaque typedefs in C++

+0

Это здорово, выглядит быть * точно *, что я ищу! Он даже отвечает на мой вопрос выше: «Хотя вы можете имитировать их достаточно хорошо для встроенных типов, использование их для определенного пользователем типа очень многословно, поэтому на самом деле для них нужна собственная поддержка». –

Смежные вопросы