To create an integer that is not an integer (or a string, not a string) and cannot advertise or downgrade it), you can only create a new type that simply means "write a new class." There is no way - at least on the base type - to inherit behavior without smoothing. A new_type<int> has no arithmetic (unless you define it).
But you can define
template<class Innertype, class Tag> class new_type { Innertype m; public: template<class... A> explicit new_type(A&&... a) :m(std::forward<A>(a)...) {} const Innertype& as_native() const { return m; } };
and complete the entire workout only once for everyone.
template<class T, class I> auto make_new_type(I&& i) { return new_type<I,T>(std::forward<I>(i)); } template<class A, class B, class T> auto operator+(const new_type<A,T>& a, const new_type<B,T>& b) { return make_new_type<T>(a.as_native()+b.as_native()); } ....
and then
struct ID_tag; typedef new_type<std::string,ID_tag> ID; struct OtehrID_tag; typedef new_type<std::string,OtehrID_tag> OtherID;
and ID and OtherID cannot be mixed in expressions.
NOTE:
indefinite return auto-function is standard for C ++ 14, but GCC accepts it in C ++ 11 as-well.
source share