template <typename Field, size_t Arity = 1, bool I = false> struct field_t { static_assert(Arity > 0 && Arity <= 200, "Invalid cardinality"); static_assert(I ? (Arity == 1) : true, "Arrays can't be keys"); constexpr static const size_t size = sizeof(Field) * Arity; constexpr static const size_t element_size = sizeof(Field); constexpr static const size_t arity = Arity; using element_type = Field; constexpr static const bool is_index = I; constexpr static const bool is_array = arity > 1; constexpr static const bool is_string = std::is_same<element_type, const char*>::value; using member_type = typename std::conditional<is_array, std::array<element_type, arity>, element_type>::type; using const_member_type = typename std::add_const<member_type>::type; using lref_member_type = typename std::add_lvalue_reference<member_type>::type; using const_lref_member_type = typename std::add_const<lref_member_type>::type; using rref_member_type = typename std::add_rvalue_reference<member_type>::type; field_t(const field_t& other) { value = other.value; } field_t(field_t&& other) { value = std::move(other.value); } field_t() { } explicit field_t(member_type value_) { value = value_; } field_t(rref_member_type value_) { value = std::move(value_); } field_t(const_lref_member_type value_) { value = value_; } field_t& operator = (const_lref_member_type value_) { value = value_; return *this; } field_t& operator = (rref_member_type value_) { value = std::move(value_); return *this; } inline operator member_type() const { return value; } //inline auto operator [] (size_t index) const -> typename std::enable_if<arity != 1, const element_type&>::type //{ // return value[index]; //} //inline auto operator [] (size_t index) -> typename std::enable_if<arity != 1, element_type&>::type //{ // return value[index]; //} private: member_type value; }; template <size_t N = 1> using string_t = field_t<const char*, N, false>; using index_t = field_t<std::uint32_t, 1, true>; using locstring_t = string_t<16>; using u64_t = field_t<std::uint64_t>; using u32_t = field_t<std::uint32_t>; using u16_t = field_t<std::uint16_t>; using u8_t = field_t<std::uint8_t>; using i64_t = field_t<std::int64_t>; using i32_t = field_t<std::int32_t>; using i16_t = field_t<std::int16_t>; using i8_t = field_t<std::int8_t>; using single_t = field_t<float>; template <typename Enum, typename... Members> struct record_t : private std::tuple<Members...> { private: using is_scoped_enum = std::integral_constant<bool, std::is_enum<Enum>::value && !std::is_convertible<Enum, int>::value>; public: static_assert(is_scoped_enum::value, "Must use get<>() with scoped enums"); static_assert(sizeof...(Members) > 0, "Can't have an empty structure."); constexpr static const size_t size = sizeof...(Members); template <size_t Idx> using member = typename details::nth_element<Idx, Members...>; template <Enum Idx> inline auto get() { typedef typename std::underlying_type<Enum>::type enum_underlying_type; return std::get<static_cast<enum_underlying_type>(Idx)>(*this); } };