Skip to content

Instantly share code, notes, and snippets.

@willkill07
Last active May 9, 2017 19:43
Show Gist options
  • Save willkill07/b645bc89339159e1cb77b0e0d836f36d to your computer and use it in GitHub Desktop.
Save willkill07/b645bc89339159e1cb77b0e0d836f36d to your computer and use it in GitHub Desktop.
Strong Typing in C++11
#include "Types.hpp"
#include "StrongType.hpp"
#define VALIDATE_TYPES 1
using FloatT = double;
#if !defined(VALIDATE_TYPES)
using Length = FloatT;
using Time = FloatT;
using Velocity = FloatT;
using Acceleration = FloatT;
#else
using Length = StrongType<FloatT, units::length>;
using Time = StrongType<FloatT, units::time>;
using Velocity = decltype(Length()/Time());
using Acceleration = decltype(Velocity()/Time());
#endif
void strong(Length* p, Velocity* v, Acceleration* a, Time* t, int N) {
for (int i = 0; i < N; ++i)
p[i] += v[i] * t[i] + 0.5 * a[i] * (t[i] * t[i]);
}
void weak(double* p, double* v, double* a, double* t, int N) {
for (int i = 0; i < N; ++i)
p[i] += v[i] * t[i] + 0.5 * a[i] * (t[i] * t[i]);
}
#include <type_traits>
template <typename T, typename Tag>
struct StrongType {
T value;
explicit StrongType(T v) : value(v) {}
StrongType() = default;
StrongType(StrongType const &) = default;
StrongType(StrongType &&) = default;
template <typename U, typename OTag>
StrongType& operator+=(StrongType<U,OTag> o) {
static_assert(std::is_same<Tag,OTag>::value, "Mismatched units");
value += o.value;
return *this;
}
template <typename U, typename OTag>
StrongType& operator-=(StrongType<U,OTag> o) {
static_assert(std::is_same<Tag,OTag>::value, "Mismatched units");
value += o.value;
return *this;
}
template <typename U, typename OTag>
StrongType& operator*=(StrongType<U,OTag> o) {
static_assert(std::is_same<Tag,OTag>::value, "Mismatched units");
value += o.value;
return *this;
}
template <typename U, typename OTag>
StrongType& operator/=(StrongType<U,OTag> o) {
static_assert(std::is_same<Tag,OTag>::value, "Mismatched units");
value += o.value;
return *this;
}
template <typename U>
StrongType& operator*=(U v) {
value += v;
return *this;
}
template <typename U>
StrongType& operator/=(U v) {
value /= v;
return *this;
}
StrongType operator-() const {
return StrongType{-value};
}
StrongType operator+() const {
return StrongType{value};
}
};
template <typename T, typename TTag, typename U, typename UTag>
auto operator+(StrongType<T,TTag> v1, StrongType<U,UTag> v2)
-> StrongType<decltype(v1.value + v2.value), TTag> {
static_assert(std::is_same<TTag,UTag>::value, "");
return StrongType<decltype(v1.value + v2.value), TTag>{v1.value + v2.value};
}
template <typename T, typename TTag, typename U, typename UTag>
auto operator-(StrongType<T,TTag> v1, StrongType<U,TTag> v2)
-> StrongType<decltype(v1.value - v2.value), TTag> {
static_assert(std::is_same<TTag,UTag>::value, "");
return StrongType<decltype(v1.value - v2.value), TTag>{v1.value - v2.value};
}
template <typename T, typename TTag, typename U, typename UTag>
auto operator*(StrongType<T,TTag> v1, StrongType<U,UTag> v2)
-> StrongType<decltype(v1.value * v2.value), typename ops::times<TTag,UTag>::type> {
return StrongType<decltype(v1.value * v2.value), typename ops::times<TTag,UTag>::type>{v1.value * v2.value};
}
template <typename T, typename TTag, typename U, typename UTag>
auto operator/(StrongType<T,TTag> v1, StrongType<U,UTag> v2)
-> StrongType<decltype(v1.value / v2.value), typename ops::frac<TTag,UTag>::type> {
return StrongType<decltype(v1.value / v2.value), typename ops::frac<TTag,UTag>::type>{v1.value / v2.value};
}
template <typename T, typename TTag, typename U, typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
StrongType<T,TTag> operator*(StrongType<T,TTag> v1, U v2) {
return StrongType<T,TTag>{v1.value * v2};
}
template <typename T, typename TTag, typename U, typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
StrongType<T,TTag> operator*(U v2, StrongType<T,TTag> v1) {
return StrongType<T,TTag>{v2 * v1.value};
}
template <typename T, typename TTag, typename U, typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
StrongType<T,TTag> operator/(StrongType<T,TTag> const v1, U const v2) {
return StrongType<T,TTag>{v1.value / v2};
}
template <typename T, typename TTag, typename U, typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
StrongType<T,TTag> operator/(U const v2, StrongType<T,TTag> const v1) {
return StrongType<T,TTag>{v2 / v1.value};
}
#include <type_traits>
#include <utility>
template <typename T, T... Is>
struct integer_sequence {};
template <unsigned int... Is>
using index_sequence = integer_sequence<unsigned int, Is...>;
namespace detail {
template <typename T, T Val, typename>
struct type_seq_push_back;
template <typename T, T Val, T... Ts, template <typename, T...> class TT>
struct type_seq_push_back<T, Val, TT<T, Ts...>> {
using type = TT<T, Ts..., Val>;
};
template <typename T, T Val, unsigned int N, template <typename, T...> class TT>
struct repeat {
using type = typename type_seq_push_back<
T, Val, typename repeat<T, Val, N - 1, TT>::type>::type;
};
template <typename T, T Val, template <typename, T...> class TT>
struct repeat<T, Val, 0, TT> {
using type = TT<T>;
};
template <unsigned int N>
struct sequence {
using type = typename type_seq_push_back<
unsigned int, N - 1, typename sequence<(N - 1)>::type>::type;
};
template <>
struct sequence<0> {
using type = integer_sequence<unsigned int>;
};
template <unsigned int N>
using make_sequence = typename detail::sequence<N>::type;
template <typename T, unsigned int Index, T NewValue, typename Indicies, T... OldValues>
struct set_impl;
template <typename T, unsigned int Index, T NewValue, T... OldValues, unsigned int... Is>
struct set_impl<T, Index, NewValue, index_sequence<Is...>, OldValues...> {
using type = integer_sequence<T, ((Index == Is) ? NewValue : OldValues)...>;
};
template <typename T, unsigned int Index, T NewValue, typename List>
struct set;
template <typename T, unsigned int Index, T NewValue, T... OldValues>
struct set<T, Index, NewValue, integer_sequence<T, OldValues...>> {
using type = typename set_impl<
T, Index, NewValue, make_sequence<sizeof...(OldValues)>, OldValues...>::type;
};
template <typename, typename T, unsigned int Index, T NewValue>
struct set_list{};
template <typename T, unsigned int Index, T NewValue, T... OldValues>
struct set_list<integer_sequence<T, OldValues...>, T, Index, NewValue> {
using type = typename set<
T, Index, NewValue, integer_sequence<T, OldValues...>>::type;
};
template <typename T, unsigned int Size>
struct make_empty_list {
using type = typename repeat<T, T(0), Size, integer_sequence>::type;
};
template <typename T, unsigned int Size, unsigned int Index, T Value>
struct make_list_with_index_value {
static_assert(Index < Size, "invalid index specified");
using type = typename set_list<
typename make_empty_list<T, Size>::type, T, Index, Value>::type;
};
}
template <unsigned int N>
using make_sequence = detail::make_sequence<N>;
template <typename T, unsigned int Size>
using make_empty_list = typename detail::make_empty_list<T, Size>::type;
template <typename T, unsigned int Size, unsigned int Index, T Value>
using make_list_with_index_value = typename detail::make_list_with_index_value<T, Size, Index, Value>::type;
namespace ops {
template <typename, typename> struct times;
template <typename T, T... T1, T... T2>
struct times<integer_sequence<T, T1...>, integer_sequence<T, T2...>> {
using type = integer_sequence<T, (T1 + T2)...>;
};
template <typename, typename> struct frac;
template <typename T, T... T1, T... T2>
struct frac<integer_sequence<T, T1...>, integer_sequence<T, T2...>> {
using type = integer_sequence<T, (T1 - T2)...>;
};
template <typename, int Value> struct pow;
template <typename T, T... T1, T Value>
struct pow<integer_sequence<T, T1...>, Value> {
using type = integer_sequence<T, (T1 * Value)...>;
};
}
namespace units {
constexpr unsigned int Dims = 7;
using length = make_list_with_index_value<int, Dims, 0, 1>;
using mass = make_list_with_index_value<int, Dims, 1, 1>;
using time = make_list_with_index_value<int, Dims, 2, 1>;
using current = make_list_with_index_value<int, Dims, 3, 1>;
using temperature = make_list_with_index_value<int, Dims, 4, 1>;
using substance = make_list_with_index_value<int, Dims, 5, 1>;
using luminous = make_list_with_index_value<int, Dims, 6, 1>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment