| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- //
- // opaque_typedef.hpp
- // opaque-type
- //
- // Inspired by https://foonathan.github.io/blog/2016/10/19/strong-typedefs.html and others
- //
- // Created by Sam Jaffe on 8/16/16.
- //
- #pragma once
- template <typename Tag, typename T>
- T underlying_type_impl(strong_typedef<Tag, T>);
- template <typename T>
- using underlying_type = decltype(underlying_type_impl(std::declval<T>()));
- #define OPAQUE_TYPE_ASSIGN_OPERATOR(name, op) \
- template <typename TDef> \
- struct name { \
- friend TDef & operator op##=(TDef & lhs, TDef const & rhs) { \
- using type = underlying_type<TDef>; \
- static_cast<type &>(lhs) op##= static_cast<type const &>(rhs); \
- return lhs; \
- } \
- \
- friend TDef operator op(TDef const & lhs, TDef const & rhs) { \
- using type = underlying_type<TDef>; \
- return TDef(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
- } \
- }
- #define OPAQUE_TYPE_BINARY_OPERATOR(name, op) \
- template <typename TDef> \
- struct name { \
- friend TDef operator op(TDef const & lhs, TDef const & rhs) { \
- using type = underlying_type<TDef>; \
- return TDef(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
- } \
- }
- #define OPAQUE_TYPE_MIXED_BINARY_OPERATOR(name, op) \
- template <typename TDef, typename RDef, typename Out> \
- struct name { \
- friend Out operator op(TDef const & lhs, RDef const & rhs) { \
- using type1 = underlying_type<TDef>; \
- using type2 = underlying_type<RDef>; \
- return Out(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
- } \
- }; \
- \
- template <typename TDef, typename RDef> \
- struct name<TDef, RDef, TDef> { \
- friend TDef operator op##=(TDef & lhs, RDef const & rhs) { \
- using type1 = underlying_type<TDef>; \
- using type2 = underlying_type<RDef>; \
- static_cast<type1 &>(lhs) op##= static_cast<type2 const&>(rhs); \
- return lhs; \
- } \
- \
- friend Out operator op(TDef const & lhs, RDef const & rhs) { \
- using type1 = underlying_type<TDef>; \
- using type2 = underlying_type<RDef>; \
- return Out(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
- } \
- }
- #define OPAQUE_TYPE_BINARY_OPERATOR(name, op) \
- template <typename TDef> \
- struct name { \
- friend TDef operator op(TDef const & val) { \
- using type = underlying_type<TDef>; \
- return TDef(op static_cast<type const&>(val)); \
- } \
- }
- OPAQUE_TYPE_UNARY_OPERATOR(unary_plus, +);
- OPAQUE_TYPE_UNARY_OPERATOR(unary_minus, -);
- OPAQUE_TYPE_ASSIGN_OPERATOR(addition, +);
- OPAQUE_TYPE_ASSIGN_OPERATOR(subtraction, -);
- OPAQUE_TYPE_ASSIGN_OPERATOR(multiplication, *);
- OPAQUE_TYPE_ASSIGN_OPERATOR(division, /);
- OPAQUE_TYPE_ASSIGN_OPERATOR(modulo, %);
- OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_addition, +);
- OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_subtraction, -);
- OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_multiplication, *);
- OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_division, /);
- OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_and, &);
- OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_or, |);
- OPAQUE_TYPE_ASSIGN_OPERATOR(exclusive_or, ^);
- template <typename TDef>
- struct numeric_arithmatic : unary_plus<TDef>, unary_minus<TDef>, addition<TDef>, subtraction<TDef>, multiplication<TDef>, division<TDef> {};
- template <typename TDef>
- struct integer_arithmatic : numeric_arithmatic<TDef>, modulo<TDef> {}
- #undef OPAQUE_TYPE_BINARY_OPERATOR
- #undef OPAQUE_TYPE_MIXED_BINARY_OPERATOR
- #undef OPAQUE_TYPE_UNARY_OPERATOR
- #undef OPAQUE_TYPE_ASSIGN_OPERATOR
- template <typename Self, typename T>
- class opaque_typedef {
- public:
- opaque_typedef() : _value() {}
- explicit opaque_typedef(T const & val) : _value(val) {}
- explicit opaque_typedef(T && val) noexcept(std::is_nothrow_move_constructible<T>::value) : _value(std::move(val)) {}
- explicit operator T &() noexcept { return _value; }
- explicit operator T const&() const noexcept { return _value; }
-
- friend void swap(opaque_typedef & lhs, opaque_typedef & rhs) {
- using std::swap;
- swap(lhs._value, rhs._value);
- }
- private:
- T _value;
- };
|