Last active
May 9, 2017 19:43
-
-
Save willkill07/b645bc89339159e1cb77b0e0d836f36d to your computer and use it in GitHub Desktop.
Strong Typing in C++11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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]); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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