Skip to content

Instantly share code, notes, and snippets.

@willkill07
Last active May 17, 2017 02:45
Show Gist options
  • Select an option

  • Save willkill07/dcd6de574130d2f2a0fe7831b7e1a500 to your computer and use it in GitHub Desktop.

Select an option

Save willkill07/dcd6de574130d2f2a0fe7831b7e1a500 to your computer and use it in GitHub Desktop.
Strong Typing in C++14
#include <type_traits>
#include <utility>
namespace detail {
template <typename Seq, std::size_t Idx, typename T, T Val, T DefaultVal>
struct make_list_with_index_value;
template <std::size_t Idx, typename T, T Val, T DefaultVal, std::size_t ... Ids>
struct make_list_with_index_value<std::index_sequence<Ids...>, Idx, T, Val, DefaultVal> {
using type = std::integer_sequence<T, ((Idx == Ids) ? Val : DefaultVal)...>;
};
}
template <std::size_t Size, std::size_t Index, typename T, T Value, T DefaultValue>
using make_list_with_index_value = typename detail::make_list_with_index_value<std::make_index_sequence<Size>, Index, T, Value, DefaultValue>::type;
namespace ops {
template <typename T1, typename T2> struct plus {
static_assert(std::is_same<T1,T2>::value, "mismatched units encountered");
using type = T1;
};
template <typename T1, typename T2> using minus = plus<T1,T2>;
template <typename, typename> struct multiplies;
template <typename, typename> struct divides;
template <typename, typename> struct pow;
template <int... T1, int... T2>
struct multiplies<std::integer_sequence<int, T1...>, std::integer_sequence<int, T2...>> {
using type = std::integer_sequence<int, (T1 + T2)...>;
};
template <int... T1, int... T2>
struct divides<std::integer_sequence<int, T1...>, std::integer_sequence<int, T2...>> {
using type = std::integer_sequence<int, (T1 - T2)...>;
};
template <int... T1, int Value>
struct pow<std::integer_sequence<int, T1...>, std::integer_sequence<int, Value>> {
using type = std::integer_sequence<int, (T1 * Value)...>;
};
}
namespace units {
constexpr unsigned int Dims = 7;
using none = make_list_with_index_value<Dims, 0, int, 0, 0>;
using length = make_list_with_index_value<Dims, 0, int, 1, 0>;
using mass = make_list_with_index_value<Dims, 1, int, 1, 0>;
using time = make_list_with_index_value<Dims, 2, int, 1, 0>;
using current = make_list_with_index_value<Dims, 3, int, 1, 0>;
using temperature = make_list_with_index_value<Dims, 4, int, 1, 0>;
using substance = make_list_with_index_value<Dims, 5, int, 1, 0>;
using luminous = make_list_with_index_value<Dims, 6, int, 1, 0>;
}
template <typename T, typename Tag>
struct StrongType {
private:
T value;
public:
using type = T;
explicit StrongType(T v) : value(v) {}
StrongType() = default;
StrongType(StrongType const &) = default;
StrongType(StrongType &&) = default;
explicit operator T() const {
return value;
};
StrongType& operator+=(const StrongType &o) {
value += o.value;
return *this;
}
StrongType& operator-=(const StrongType &o) {
value -= o.value;
return *this;
}
template <typename U, typename = typename std::enable_if<std::is_arithmetic<U>::type>>
StrongType& operator*=(U v) {
value += v;
return *this;
}
template <typename U, typename = typename std::enable_if<std::is_arithmetic<U>::type>>
StrongType& operator/=(U v) {
value /= v;
return *this;
}
StrongType operator-() const {
return StrongType{-value};
}
StrongType operator+() const {
return StrongType{value};
}
#define GEN_OP(BINOP, FN_TAG) \
template < \
typename U, typename UTag, \
typename Ret = StrongType<decltype(T() BINOP U()), typename FN_TAG <Tag,UTag>::type>> \
Ret operator BINOP(const StrongType<U, UTag> & o) const { \
return Ret{value BINOP static_cast<U>(o)}; \
}
GEN_OP(+,ops::plus)
GEN_OP(-,ops::minus)
GEN_OP(*,ops::multiplies)
GEN_OP(/,ops::divides)
#undef GEN_OP
};
#define GEN_OP(BINOP, FN_TAG) \
template <typename T, typename Tag, typename U, \
typename Ret = StrongType<decltype(T() BINOP U()), typename FN_TAG <Tag, units::none>::type>, \
typename = typename std::enable_if<std::is_arithmetic<U>::value>::type> \
Ret operator BINOP(StrongType<T,Tag> const & v1, U const v2) { \
return Ret{static_cast<T>(v1) BINOP v2}; \
} \
\
template <typename T, typename Tag, typename U, \
typename Ret = StrongType<decltype(U() BINOP T()), typename FN_TAG <units::none, Tag>::type>, \
typename = typename std::enable_if<std::is_arithmetic<U>::value>::type> \
Ret operator BINOP(U const v1, StrongType<T,Tag> const & v2) { \
return Ret{v1 BINOP static_cast<T>(v2)}; \
}
GEN_OP(*,ops::multiplies)
GEN_OP(/,ops::divides)
#undef GEN_OP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment