I would like if possible to remove the x y function that i add to reflect correctly my base class
but when i try to invoke x() or y() without my trick it's not a valid pointer to member
namespace antara::gaming::math
{
template<class Unit, size_t Size, template<class> class...Mixins>
class basic_vector : public Mixins<basic_vector<Unit, Size, Mixins...>> ...
{
template<class, size_t, template<class> class...>
friend
class basic_vector;
using sequence_type = std::make_index_sequence<Size>;
template<class Res, size_t...Is>
constexpr auto implicit_cast_to(std::index_sequence<Is...>) const noexcept
{
return Res{std::get<Is>(data_)...};
}
template<class Res, size_t...Is>
constexpr auto explicit_cast_to(std::index_sequence<Is...>) const noexcept
{
using NewUnit = typename Res::value_type;
return Res{static_cast<NewUnit>(std::get<Is>(data_))...};
}
template<class F, size_t...Is>
constexpr basic_vector make_vec(F &&f, std::index_sequence<Is...>) const noexcept
{
return {f(std::get<Is>(data_))...};
}
template<class F, size_t...Is>
constexpr basic_vector make_vec(F &&f, basic_vector const &rhs, std::index_sequence<Is...>) const noexcept
{
return {f(std::get<Is>(data_), std::get<Is>(rhs.data_))...};
}
template<class F, size_t...Is>
constexpr void update_vec(F &&f, std::index_sequence<Is...>) noexcept
{
(f(std::get<Is>(data_)), ...);
}
template<class F, size_t...Is>
constexpr void update_vec(F &&f, basic_vector const &rhs, std::index_sequence<Is...>) noexcept
{
(f(std::get<Is>(data_), std::get<Is>(rhs.data_)), ...);
}
template<size_t...Is>
constexpr Unit square_length(std::index_sequence<Is...>) const noexcept
{
return (... + (std::get<Is>(data_) * std::get<Is>(data_)));
}
template<class F, class Vec, size_t...Is>
constexpr bool test_predicate(F &&f, Vec const &rhs, std::index_sequence<Is...>) const noexcept
{
return (f(std::get<Is>(data_), std::get<Is>(rhs.data_)) && ...);
}
std::array<Unit, Size> data_;
public:
using value_type = Unit;
// Aggregate-like constructor
template<class...Args, class = std::enable_if_t<
std::conjunction_v<std::is_convertible<Args, Unit>...>
>>
constexpr basic_vector(Args...args) noexcept : data_{args...}
{}
constexpr basic_vector(Unit single_value) noexcept
{
std::fill(begin(), end(), single_value);
}
static constexpr auto scalar(Unit single_value) noexcept
{
return basic_vector(single_value);
}
constexpr Unit operator[](int i) const noexcept
{ return data_[i]; }
constexpr Unit &operator[](int i) noexcept
{ return data_[i]; }
template<size_t I>
constexpr Unit get() const noexcept
{
static_assert(I >= 0 && I < Size, "Index outside of bounds");
return std::get<I>(data_);
}
template<size_t I>
constexpr Unit &get() noexcept
{
static_assert(I >= 0 && I < Size, "Index outside of bounds");
return std::get<I>(data_);
}
constexpr Unit *data() noexcept
{ return data_.data(); }
constexpr Unit const *data() const noexcept
{ return data_.data(); }
constexpr int size() const noexcept
{ return Size; }
constexpr auto begin() noexcept
{ return data_.begin(); }
constexpr auto begin() const noexcept
{ return data_.begin(); }
constexpr auto end() noexcept
{ return data_.end(); }
constexpr auto end() const noexcept
{ return data_.end(); }
// Implicit cast
template<class NewUnit, template<class> class...NewMixins>
constexpr operator basic_vector<NewUnit, Size, NewMixins...>() const noexcept
{
static_assert(std::is_convertible_v<Unit, NewUnit>, "Impossible cast from [value_type] to [NewUnit]");
return implicit_cast_to<basic_vector<NewUnit, Size, NewMixins...>>(sequence_type{});
}
// Explicit cast
template<class Vec>
constexpr Vec to() const noexcept
{
using NewUnit = typename Vec::value_type;
static_assert(std::is_convertible_v<Unit, NewUnit>,
"Impossible cast from [value_type] to [Vec::value_type]");
return explicit_cast_to<Vec>(sequence_type{});
}
constexpr basic_vector operator+(Unit b) const noexcept
{
return make_vec([b](Unit a) { return a + b; }, sequence_type{});
}
constexpr basic_vector operator-(Unit b) const noexcept
{
return make_vec([b](Unit a) { return a - b; }, sequence_type{});
}
constexpr basic_vector operator*(Unit b) const noexcept
{
return make_vec([b](Unit a) { return a * b; }, sequence_type{});
}
constexpr basic_vector operator/(Unit b) const noexcept
{
return make_vec([b](Unit a) { return a / b; }, sequence_type{});
}
constexpr basic_vector operator+(basic_vector const &rhs) const noexcept
{
return make_vec([](Unit a, Unit b) { return a + b; }, rhs, sequence_type{});
}
constexpr basic_vector operator-(basic_vector const &rhs) const noexcept
{
return make_vec([](Unit a, Unit b) { return a - b; }, rhs, sequence_type{});
}
constexpr basic_vector operator*(basic_vector const &rhs) const noexcept
{
return make_vec([](Unit a, Unit b) { return a * b; }, rhs, sequence_type{});
}
constexpr basic_vector operator/(basic_vector const &rhs) const noexcept
{
return make_vec([](Unit a, Unit b) { return a / b; }, rhs, sequence_type{});
}
constexpr basic_vector &operator+=(Unit b) noexcept
{
update_vec([b](Unit &a) { a += b; }, sequence_type{});
return *this;
}
constexpr basic_vector &operator-=(Unit b) noexcept
{
update_vec([b](Unit &a) { a -= b; }, sequence_type{});
return *this;
}
constexpr basic_vector &operator*=(Unit b) noexcept
{
update_vec([b](Unit &a) { a *= b; }, sequence_type{});
return *this;
}
constexpr basic_vector &operator/=(Unit b) noexcept
{
update_vec([b](Unit &a) { a /= b; }, sequence_type{});
return *this;
}
constexpr basic_vector &operator+=(basic_vector const &rhs) noexcept
{
update_vec([](Unit &a, Unit b) { a += b; }, rhs, sequence_type{});
return *this;
}
constexpr basic_vector &operator-=(basic_vector const &rhs) noexcept
{
update_vec([](Unit &a, Unit b) { a -= b; }, rhs, sequence_type{});
return *this;
}
constexpr basic_vector &operator*=(basic_vector const &rhs) noexcept
{
update_vec([](Unit &a, Unit b) { a *= b; }, rhs, sequence_type{});
return *this;
}
constexpr basic_vector &operator/=(basic_vector const &rhs) noexcept
{
update_vec([](Unit &a, Unit b) { a /= b; }, rhs, sequence_type{});
return *this;
}
constexpr basic_vector operator-() const noexcept
{
return make_vec([](Unit x) { return -x; }, sequence_type{});
}
constexpr Unit square_length() const noexcept
{
return square_length(sequence_type{});
}
constexpr Unit length() const noexcept
{
return std::sqrt(square_length());
}
constexpr basic_vector normalized() const noexcept
{
return *this / length();
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator==(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return test_predicate([](Unit a, Unit b) { return a == b; }, rhs, sequence_type{});
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator!=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return !(*this == rhs);
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator<(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return test_predicate([](Unit a, Unit b) { return a < b; }, rhs, sequence_type{});
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator>=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return !(*this < rhs);
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator>(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return rhs < *this;
}
template<class NewUnit, template<class> class...NewMixins>
constexpr bool operator<=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
{
return !(rhs < *this);
}
};
namespace vector_mixins
{
template<class Derived>
class access_xy
{
public:
constexpr auto x() const noexcept
{ return static_cast<Derived const *>(this)->template get<0>(); }
constexpr auto &x() noexcept
{ return static_cast<Derived *>(this)->template get<0>(); }
constexpr auto y() const noexcept
{ return static_cast<Derived const *>(this)->template get<1>(); }
constexpr auto &y() noexcept
{ return static_cast<Derived *>(this)->template get<1>(); }
};
template<class Derived>
class access_z
{
public:
constexpr auto z() const noexcept
{ return static_cast<Derived const *>(this)->template get<2>(); }
constexpr auto &z() noexcept
{ return static_cast<Derived *>(this)->template get<2>(); }
};
}
template<class Unit>
using vec2 = basic_vector<Unit, 2, vector_mixins::access_xy>;
using vec2c = vec2<char>;
using vec2uc = vec2<unsigned char>;
using vec2s = vec2<short>;
using vec2us = vec2<unsigned short>;
using vec2i = vec2<int>;
using vec2u = vec2<unsigned>;
using vec2l = vec2<long>;
using vec2ul = vec2<unsigned long>;
using vec2ll = vec2<long long>;
using vec2ull = vec2<unsigned long long>;
using vec2f = vec2<float>;
using vec2d = vec2<double>;
using vec2ld = vec2<long double>;
template<class Unit>
using vec3 = basic_vector<Unit, 3, vector_mixins::access_xy, vector_mixins::access_z>;
using vec3c = vec3<char>;
using vec3uc = vec3<unsigned char>;
using vec3s = vec3<short>;
using vec3us = vec3<unsigned short>;
using vec3i = vec3<int>;
using vec3u = vec3<unsigned>;
using vec3l = vec3<long>;
using vec3ul = vec3<unsigned long>;
using vec3ll = vec3<long long>;
using vec3ull = vec3<unsigned long long>;
using vec3f = vec3<float>;
using vec3d = vec3<double>;
using vec3ld = vec3<long double>;
}
namespace std {
template<class Unit, size_t Size, template<class> class...Mixins>
struct tuple_size<antara::gaming::math::basic_vector<Unit, Size, Mixins...>> : integral_constant<size_t, Size> {};
template <size_t I, class Unit, size_t Size, template<class> class...Mixins>
struct tuple_element<I, antara::gaming::math::basic_vector<Unit, Size, Mixins...>> { using type = Unit; };
}