Skip to content

Instantly share code, notes, and snippets.

@Nekrolm
Last active October 27, 2019 10:24
Show Gist options
  • Save Nekrolm/0b2e78559125b15e0e86daf545b6f713 to your computer and use it in GitHub Desktop.
Save Nekrolm/0b2e78559125b15e0e86daf545b6f713 to your computer and use it in GitHub Desktop.
simple strong_typedef system implementation
#include <type_traits>
#include <utility>
#include <iostream>
#define DECLARE_TAG_CHECKER(TAG_NAME) \
template <class T, class = void> \
struct has_##TAG_NAME##_tag : std::false_type {}; \
\
template <class T> \
struct has_##TAG_NAME##_tag<T, decltype(std::declval<typename T::TAG_NAME>(), void(0))> : std::true_type {}; \
\
template <class T> \
constexpr bool has_##TAG_NAME##_tag_v = has_##TAG_NAME##_tag<T>::value;
DECLARE_TAG_CHECKER(is_comparable)
DECLARE_TAG_CHECKER(is_additive)
DECLARE_TAG_CHECKER(is_subtractive)
template<class TypeAlias, class UnderlyingType>
struct StrongTypedef {
StrongTypedef() = default;
explicit StrongTypedef(const UnderlyingType& val) : value(val) {}
explicit StrongTypedef(UnderlyingType&& val) : value(std::move(val)) {}
const UnderlyingType& Value() const {
return value;
}
bool operator == (const TypeAlias& rhs) const {
static_assert(has_is_comparable_tag_v<TypeAlias>,
"add using StrongTypedef::is_comparable to enable");
return Value() == rhs.Value();
}
bool operator < (const TypeAlias& rhs) const {
static_assert(has_is_comparable_tag_v<TypeAlias>,
"add using StrongTypedef::is_comparable to enable");
return Value() < rhs.Value();
}
TypeAlias& operator += (const TypeAlias& rhs) {
static_assert(has_is_additive_tag_v<TypeAlias>,
"add using StrongTypedef::is_additive to enable");
value += rhs.Value();
return *as_type();
}
TypeAlias& operator -= (const TypeAlias& rhs) {
static_assert(has_is_subtractive_tag_v<TypeAlias>,
"add using StrongTypedef::is_subtractive to enable");
value -= rhs.Value();
return *as_type();
}
friend TypeAlias operator + (const TypeAlias& lhs, const TypeAlias& rhs) {
auto tmp = lhs;
tmp += rhs;
return tmp;
}
friend TypeAlias operator - (const TypeAlias& lhs, const TypeAlias& rhs) {
auto tmp = lhs;
tmp -= rhs;
return tmp;
}
protected:
struct is_comparable {};
struct is_additive {};
struct is_subtractive {};
private:
UnderlyingType value;
TypeAlias* as_type() {
return static_cast<TypeAlias*>(this);
}
const TypeAlias* as_type() const {
return static_cast<const TypeAlias*>(this);
}
};
//---- DEMO ------
struct Meter : StrongTypedef<Meter, double> {
using StrongTypedef::is_comparable;
using StrongTypedef::is_additive;
using StrongTypedef::is_subtractive;
using StrongTypedef::StrongTypedef;
};
struct Rank : StrongTypedef<Rank, int> {
using StrongTypedef::is_comparable;
using StrongTypedef::StrongTypedef;
};
struct Naturals : StrongTypedef<Naturals, uint64_t> {
using StrongTypedef::is_comparable;
using StrongTypedef::is_additive;
using StrongTypedef::StrongTypedef;
};
int main(){
Meter m1 {5};
Meter m2 {6};
std::cout << m1.Value() << std::endl;
std::cout << m2.Value() << std::endl;
std::cout << (m2 - m1).Value() << std::endl;
auto r1 = Rank(1);
auto r2 = Rank(2);
std::cout << (r1 < r2) << std::endl;
// std::cout << (r1 + r2).Value() << std::endl; //compilation error
auto n1 = Naturals(5);
auto n2 = Naturals(7);
std::cout << (n1 + n2).Value() << std::endl;
// std::cout << (n2 - n1).Value() << std::endl; // compilation error
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment