Векторная реализация классов в C++


я переписал вектора классы похожи на олм - библиотека, которая используется в основном для OpenGL приложений.

я хотел бы знать, как я могу улучшить его дальше ?

Типов.ГЭС

#pragma once


#include <type_traits>
#include <cctype>
#include <cfloat>
#include <limits>
#include <bitset>
#include <iostream>
#include <iomanip>
#include <algorithm>
#ifdef _MSC_VER
typedef unsigned __int64    uint64;
#else
typedef uint64_t            uint64;
#endif

#ifdef _MSC_VER
typedef __int64                 int64;
#else
typedef int64_t                 int64;
#endif

#ifdef _MSC_VER
typedef unsigned __int32    uint32;
#else
typedef uint32_t            uint32;
#endif

#ifdef _MSC_VER
typedef __int32                 int32;
#else
typedef int32_t                 int32;
#endif

#ifdef _MSC_VER
typedef unsigned __int16    uint16;
#else
typedef uint16_t            uint16;
#endif

#ifdef _MSC_VER
typedef __int16                 int16;
#else
typedef int16_t                 int16;
#endif

#ifdef _MSC_VER
typedef unsigned __int8     uint8;
#else
typedef uint8_t             uint8;
#endif

#ifdef _MSC_VER
typedef signed __int8                   int8;
#else
typedef signed int8_t                   int8;
#endif
template <size_t size>
struct Types {
    typedef void int_type;
};

template <>
struct Types<4> {
    typedef int int_type;
    typedef unsigned int uint_type;
};

template <>
struct Types<8> {
    typedef __int64 int_type;
    typedef unsigned __int64 uint_type;
};

template <typename T>
class Float
{
public:
    typedef typename Types<sizeof(T)>::uint_type bit_type;
    typedef typename T value_type;

    static const bit_type bit_count = 8 * sizeof(value_type);
    static const bit_type fraction_count = std::numeric_limits<value_type>::digits - 1;
    static const bit_type exponent_count = bit_count - 1 - fraction_count;

    static const bit_type sign_mask = static_cast<bit_type>(1) << (bit_count - 1);
    static const bit_type fraction_mask = ~static_cast<bit_type>(0) >> (exponent_count + 1);
    static const bit_type exponent_mask = ~(sign_mask | fraction_mask);
    static const bit_type max_ulps = static_cast<bit_type>(4);

    explicit Float(const T& x) { value = x; }

    const value_type &data_float() const { return value; }
    const bit_type &data_bits() const { return bit; }

    bit_type exponent_bits() const { return (exponent_mask & bit); }
    bit_type sign_bits() const { return sign; }
    bit_type fraction_bits() const { return fraction; }

    bool is_infinity()
    {
        return ((bit & ~sign_mask) == exponent_mask);
    }

    bool is_nan() const {
        bool nan = true;
        nan &= (exponent_mask & bit) == exponent_mask;
        nan &= (fraction_mask & bit) != static_cast<bit_type>(0);
        return nan;
    }

    static bit_type to_biased(bit_type bits) {
        return (sign_mask & bits) ? (~bits + 1) : (sign_mask | bits);
    }

    static bit_type distance(bit_type bits1, bit_type bits2) {
        const bit_type biased1 = to_biased(bits1);
        const bit_type biased2 = to_biased(bits2);
        return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
    }

private:
    union
    {
        value_type value;
        bit_type bit;

        struct {
            bit_type fraction : fraction_count;
            bit_type exponent : exponent_count;
            bit_type sign : 1;
        };
    };
};

#define PRINT_DEBUG_INFO 0

template <typename T> static inline
std::enable_if_t<std::is_floating_point<T>::value, bool>
almost_equals(const T& lhs, const T& rhs)
{
    Float<T> f1(lhs), f2(rhs);

#if PRINT_DEBUG_INFO
    std::cout << std::setfill(' ') << f1 << '\n' << f2;
    std::cout << std::setfill('-') << std::setw(71) << ' ' << std::setfill(' ') << std::endl;
#endif

    const Float<T>::bit_type distance = Float<T>::distance(f1.data_bits(), f2.data_bits());
    const T abs_f1 = std::abs(f1.data_float());
    const T abs_f2 = std::abs(f2.data_float());
    const T diff = std::max(std::abs(abs_f1 - abs_f2), std::numeric_limits<T>::min());
    const T sum = std::min(std::abs(abs_f1 + abs_f2), std::numeric_limits<T>::max());

    static const T tolerance = static_cast<T>(0.000001);

    bool under_flow = abs_f1 < std::numeric_limits<T>::min() || abs_f2 < std::numeric_limits<T>::min();
    bool over_flow = abs_f1 > std::numeric_limits<T>::max() || abs_f2 > std::numeric_limits<T>::max();

    bool sign = (f1.sign_bits() ^ f2.sign_bits()) == 1 && !(under_flow ^ over_flow);

    bool inff = (f1.is_infinity() ^ f2.is_infinity()) == 1;
    bool nan = (f1.is_nan() ^ f2.is_nan()) == 1;

    bool assign = f1.data_float() == f2.data_float();
    bool ulp = distance < Float<T>::max_ulps;
    bool fixed_epsilon = diff < tolerance;
    bool relative_epsilon = diff < std::numeric_limits<T>::epsilon() * sum;

#if PRINT_DEBUG_INFO
    std::cout << "\n"
        << "distance         = " << distance << '\n'
        << "diff             = " << diff << '\n'
        << "sum              = " << sum << '\n'
        << "min              = " << std::numeric_limits<T>::min() << '\n'
        << "max              = " << std::numeric_limits<T>::max() << '\n'
        << "---------------- \n"
        << std::boolalpha
        << std::setw(15) << "under_flow       = " << std::setw(7) << under_flow << '\n'
        << std::setw(15) << "over_flow        = " << std::setw(7) << over_flow << '\n'
        << std::setw(15) << "diff sign        = " << std::setw(7) << sign << '\n'
        << std::setw(15) << "inf              = " << std::setw(7) << inff << '\n'
        << std::setw(15) << "nan              = " << std::setw(7) << nan << '\n'
        << "---------------- \n"
        << std::setw(15) << "assign           = " << std::setw(7) << assign << '\n'
        << std::setw(15) << "ulp              = " << std::setw(7) << ulp << '\n'
        << std::setw(15) << "fixed_epsilon    = " << std::setw(7) << fixed_epsilon << '\n'
        << std::setw(15) << "relative_epsilon = " << std::setw(7) << relative_epsilon << "\n\n";
    std::cout << std::setfill('-') << std::setw(71) << ' ' << std::setfill(' ') << "\n\n";
#endif

    if (sign || nan || inff) return false;

    return assign || ulp || fixed_epsilon || relative_epsilon;
}

// -- debug prints --
template <typename T> static inline std::ostream&
operator<<(std::ostream& os, const Float<T>& f)
{
    os << std::fixed << std::setprecision(25) << std::left;

    os << "float    = " << std::setw(10) << std::dec << f.data_float() << "\n";

    os << "bits     = " << std::setw(10) << std::dec << f.data_bits() << " : 0x"
        << std::setw(10) << std::hex << f.data_bits() << " : "
        << std::setw(32) << std::bitset<32>(f.data_bits()) << "\n";

    os << "sign     = " << std::setw(10) << std::dec << f.sign_bits() << " : 0x"
        << std::setw(10) << std::hex << f.sign_bits() << " : "
        << std::setw(32) << std::bitset<32>(f.sign_bits()) << "\n";

    os << "exponent = " << std::setw(10) << std::dec << f.exponent_bits() << " : 0x"
        << std::setw(10) << std::hex << f.exponent_bits() << " : "
        << std::setw(32) << std::bitset<32>(f.exponent_bits()) << "\n";

    os << "fraction = " << std::setw(10) << std::dec << f.fraction_bits() << " : 0x"
        << std::setw(10) << std::hex << f.fraction_bits() << " : "
        << std::setw(32) << std::bitset<32>(f.fraction_bits()) << "\n\n";

    os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield) << std::dec;
    return os;
}

векторы,ГЭС

#pragma once


#include <cmath>
#include <cassert>
#include "Types.hpp"

enum ctor { uninitialize };

template <typename T>
struct Vec4;

template <typename T>
struct Vec3;

template <typename T>
struct Vec2
{
    typedef typename Vec2<T> type;
    typedef typename Vec2<bool> bool_type;
    typedef typename T value_type;

    union { struct { T x, y; }; struct { T u, v; }; };

    enum { size = 2 };

    Vec2() :x(), y() {}

    explicit Vec2(ctor) {}

    explicit Vec2(T s) :x(s), y(s) {}

    Vec2(T a, T b) :x(a), y(b) {}

    // -- Conversion Constructions --
    template <typename A, typename B>
    Vec2(const A& a, const B& b)
        : x(static_cast<T>(a)), y(static_cast<T>(b)) {}

    template <typename U>
    Vec2(const Vec2<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)) {}

    template <typename U>
    explicit Vec2(const Vec3<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)) {}

    template <typename U>
    explicit Vec2(const Vec4<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)) {}

    value_type & operator[](unsigned int index) { return (&x)[index]; }
    const value_type & operator[](unsigned int index) const { return (&x)[index]; }

    template <typename U>
    Vec2 & operator=(const Vec2<U>& v)
    {
        this->x = static_cast<T>(v.x);
        this->y = static_cast<T>(v.y);
        return *this;
    }

    // -- Binary operators --
    template <typename U>
    Vec2 & operator+=(U s)
    {
        this->x += static_cast<T>(s);
        this->y += static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec2 & operator+=(const Vec2<U>& v)
    {
        this->x += static_cast<T>(v.x);
        this->y += static_cast<T>(v.y);
        return *this;
    }
    template <typename U>
    Vec2 & operator-=(U s)
    {
        this->x -= static_cast<T>(s);
        this->y -= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec2 & operator-=(const Vec2<U>& v)
    {
        this->x -= static_cast<T>(v.x);
        this->y -= static_cast<T>(v.y);
        return *this;
    }

    template <typename U>
    Vec2 & operator*=(U s)
    {
        this->x *= static_cast<T>(s);
        this->y *= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec2 & operator*=(const Vec2<U>& v)
    {
        this->x *= static_cast<T>(v.x);
        this->y *= static_cast<T>(v.y);
        return *this;
    }

    template <typename U>
    Vec2 & operator/=(U s)
    {
        this->x /= static_cast<T>(s);
        this->y /= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec2 & operator/=(const Vec2<U>& v)
    {
        this->x /= static_cast<T>(v.x);
        this->y /= static_cast<T>(v.y);
        return *this;
    }

    // -- incremental operations --
    Vec2 & operator++()
    {
        ++this->x;
        ++this->y;
        return *this;
    }
    Vec2 & operator--()
    {
        --this->x;
        --this->y;
        return *this;
    }
    Vec2 operator++(int)
    {
        Vec2<T> result(*this);
        ++*this;
        return result;
    }
    Vec2 operator--(int)
    {
        Vec2<T> result(*this);
        --*this;
        return result;
    }
};

typedef Vec2<float> vec2;
typedef Vec2<double> dvec2;
typedef Vec2<int> ivec2;
typedef Vec2<unsigned int> uivec2;
typedef Vec2<signed int> sivec2;
typedef Vec2<char> cvec2;
typedef Vec2<unsigned char> ucvec2;
typedef Vec2<signed char> scvec2;
typedef Vec2<short> shvec2;
typedef Vec2<unsigned short> ushvec2;
typedef Vec2<signed short> sshvec2;

template <typename T>
struct Vec3
{
    typedef typename Vec3<T> type;
    typedef typename Vec3<bool> bool_type;
    typedef typename T value_type;

    union { struct { T x, y, z; }; struct { T r, g, b; }; };

    enum { size = 3 };

    Vec3() :x(), y(), z() {}

    explicit Vec3(ctor) {}

    explicit Vec3(T s) :x(s), y(s), z(s) {}

    Vec3(T a, T b, T c) :x(a), y(b), z(c) {}

    // -- Conversion Constructions --
    template <typename A, typename B, typename C>
    Vec3(const A& a, const B& b, const C& c)
        : x(static_cast<T>(a)), y(static_cast<T>(b)), z(static_cast<T>(c)) {}

    template <typename U>
    explicit Vec3(const Vec2<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(0)) {}

    template <typename U, typename V>
    explicit Vec3(const Vec2<U>& v, V z)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(z)) {}

    template <typename U>
    explicit Vec3(const Vec3<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(v.z)) {}

    template <typename U>
    explicit Vec3(const Vec4<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(v.z)) {}

    value_type & operator[](unsigned int index) { return (&x)[index]; }
    const value_type & operator[](unsigned int index) const { return (&x)[index]; }

    template <typename U>
    Vec3 & operator=(const Vec3<U>& v)
    {
        this->x = static_cast<T>(v.x);
        this->y = static_cast<T>(v.y);
        this->z = static_cast<T>(v.z);
        return *this;
    }

    // -- Binary operators --
    template <typename U>
    Vec3 & operator+=(U s)
    {
        this->x += static_cast<T>(s);
        this->y += static_cast<T>(s);
        this->z += static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec3 & operator+=(const Vec3<U>& v)
    {
        this->x += static_cast<T>(v.x);
        this->y += static_cast<T>(v.y);
        this->z += static_cast<T>(v.z);
        return *this;
    }

    template <typename U>
    Vec3 & operator-=(U s)
    {
        this->x -= static_cast<T>(s);
        this->y -= static_cast<T>(s);
        this->z -= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec3 & operator-=(const Vec3<U>& v)
    {
        this->x -= static_cast<T>(v.x);
        this->y -= static_cast<T>(v.y);
        this->z -= static_cast<T>(v.z);
        return *this;
    }

    template <typename U>
    Vec3 & operator*=(U s)
    {
        this->x *= static_cast<T>(s);
        this->y *= static_cast<T>(s);
        this->z *= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec3 & operator*=(const Vec3<U>& v)
    {
        this->x *= static_cast<T>(v.x);
        this->y *= static_cast<T>(v.y);
        this->z *= static_cast<T>(v.z);
        return *this;
    }

    template <typename U>
    Vec3 & operator/=(U s)
    {
        this->x /= static_cast<T>(s);
        this->y /= static_cast<T>(s);
        this->z /= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec3 & operator/=(const Vec3<U>& v)
    {
        this->x /= static_cast<T>(v.x);
        this->y /= static_cast<T>(v.y);
        this->z /= static_cast<T>(v.z);
        return *this;
    }

    // -- incremental operations --
    Vec3 & operator++()
    {
        ++this->x;
        ++this->y;
        ++this->z;
        return *this;
    }
    Vec3 & operator--()
    {
        --this->x;
        --this->y;
        --this->z;
        return *this;
    }
    Vec3 operator++(int)
    {
        Vec3<T> result(*this);
        ++*this;
        return result;
    }
    Vec3 operator--(int)
    {
        Vec3<T> result(*this);
        --*this;
        return result;
    }
};

typedef Vec3<float> vec3;
typedef Vec3<double> dvec3;
typedef Vec3<int> ivec3;
typedef Vec3<unsigned int> uivec3;
typedef Vec3<signed int> sivec3;
typedef Vec3<char> cvec3;
typedef Vec3<unsigned char> ucvec3;
typedef Vec3<signed char> scvec3;
typedef Vec3<short> shvec3;
typedef Vec3<unsigned short> ushvec3;
typedef Vec3<signed short> sshvec3;

template <typename T>
struct Vec4
{
    typedef typename Vec4<T> type;
    typedef typename Vec4<bool> bool_type;
    typedef typename T value_type;

    union { struct { T x, y, z, w; }; struct { T r, g, b, a; }; };

    enum { size = 4 };

    Vec4() :x(), y(), z(), w() {}

    explicit Vec4(ctor) {}

    explicit Vec4(T s) :x(s), y(s), z(s), w(s) {}

    Vec4(T a, T b, T c, T d) :x(a), y(b), z(c), w(d) {}

    // -- Conversion Constructions --
    template <typename A, typename B, typename C, typename D>
    Vec4(const A& a, const B& b, const C& c, const D& d)
        : x(static_cast<T>(a)), y(static_cast<T>(b)), z(static_cast<T>(c)), w(static_cast<T>(d)) {}

    template <typename U>
    explicit Vec4(const Vec2<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(0)), w(static_cast<T>(0)) {}
    template <typename U, typename V>
    explicit Vec4(const Vec2<U>& v, V z, V w)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(z)), w(static_cast<T>(w)) {}

    template <typename U>
    explicit Vec4(const Vec3<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(v.z)), w(static_cast<T>(0)) {}
    template <typename U, typename V>
    explicit Vec4(const Vec3<U>& v, V w)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(v.z)), w(static_cast<T>(w)) {}

    template <typename U>
    explicit Vec4(const Vec4<U>& v)
        : x(static_cast<T>(v.x)), y(static_cast<T>(v.y)), z(static_cast<T>(v.z)), w(static_cast<T>(v.w)) {}

    value_type & operator[](unsigned int index) { return (&x)[index]; }
    const value_type & operator[](unsigned int index) const { return (&x)[index]; }

    template <typename U>
    Vec4 & operator=(const Vec4<U>& v)
    {
        this->x = static_cast<T>(v.x);
        this->y = static_cast<T>(v.y);
        this->z = static_cast<T>(v.z);
        this->w = static_cast<T>(v.w);
        return *this;
    }

    // -- Binary operators --
    template <typename U>
    Vec4 & operator+=(U s)
    {
        this->x += static_cast<T>(s);
        this->y += static_cast<T>(s);
        this->z += static_cast<T>(s);
        this->w += static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec4 & operator+=(const Vec4<U>& v)
    {
        this->x += static_cast<T>(v.x);
        this->y += static_cast<T>(v.y);
        this->z += static_cast<T>(v.z);
        this->w += static_cast<T>(v.w);
        return *this;
    }

    template <typename U>
    Vec4 & operator-=(U s)
    {
        this->x -= static_cast<T>(s);
        this->y -= static_cast<T>(s);
        this->z -= static_cast<T>(s);
        this->w -= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec4 & operator-=(const Vec4<U>& v)
    {
        this->x -= static_cast<T>(v.x);
        this->y -= static_cast<T>(v.y);
        this->z -= static_cast<T>(v.z);
        this->w -= static_cast<T>(v.w);
        return *this;
    }

    template <typename U>
    Vec4 & operator*=(U s)
    {
        this->x *= static_cast<T>(s);
        this->y *= static_cast<T>(s);
        this->z *= static_cast<T>(s);
        this->w *= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec4 & operator*=(const Vec4<U>& v)
    {
        this->x *= static_cast<T>(v.x);
        this->y *= static_cast<T>(v.y);
        this->z *= static_cast<T>(v.z);
        this->w *= static_cast<T>(v.w);
        return *this;
    }

    template <typename U>
    Vec4 & operator/=(U s)
    {
        this->x /= static_cast<T>(s);
        this->y /= static_cast<T>(s);
        this->z /= static_cast<T>(s);
        this->w /= static_cast<T>(s);
        return *this;
    }
    template <typename U>
    Vec4 & operator/=(const Vec4<U>& v)
    {
        this->x /= static_cast<T>(v.x);
        this->y /= static_cast<T>(v.y);
        this->z /= static_cast<T>(v.z);
        this->w /= static_cast<T>(v.w);
        return *this;
    }

    // -- incremental operations --
    Vec4 & operator++()
    {
        ++this->x;
        ++this->y;
        ++this->z;
        ++this->w;
        return *this;
    }
    Vec4 & operator--()
    {
        --this->x;
        --this->y;
        --this->z;
        --this->w;
        return *this;
    }
    Vec4 operator++(int)
    {
        Vec4<T> result(*this);
        ++*this;
        return result;
    }
    Vec4 operator--(int)
    {
        Vec4<T> result(*this);
        --*this;
        return result;
    }
};

typedef Vec4<float> vec4;
typedef Vec4<double> dvec4;
typedef Vec4<int> ivec4;
typedef Vec4<unsigned int> uivec4;
typedef Vec4<signed int> sivec4;
typedef Vec4<char> cvec4;
typedef Vec4<unsigned char> ucvec4;
typedef Vec4<signed char> scvec4;
typedef Vec4<short> shvec4;
typedef Vec4<unsigned short> ushvec4;
typedef Vec4<signed short> sshvec4;

template <typename T>
struct is_vector : std::false_type {};
template <typename T>
struct is_vector<Vec2<T>> : std::true_type {};
template <typename T>
struct is_vector<Vec3<T>> : std::true_type {};
template <typename T>
struct is_vector<Vec4<T>> : std::true_type {};

template <typename T>
struct is_vector2 : std::false_type {};
template <typename T>
struct is_vector2<Vec2<T>> : std::true_type {};

template <typename T>
struct is_vector3 : std::false_type {};
template <typename T>
struct is_vector3<Vec3<T>> : std::true_type {};

template <typename T>
struct is_vector4 : std::false_type {};
template <typename T>
struct is_vector4<Vec4<T>> : std::true_type {};

// -- Unary operators --
template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator+(const T& v)
{
    return v;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator-(const T& v)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = -v[i];
    return result;
}

// -- Binary operators --
template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator+(const T& v, const typename T::value_type& s)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v[i] + s;
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator+(const typename T::value_type& s, const T& v)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = s + v[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator+(const T& v1, const T& v2)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v1[i] + v2[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator-(const T& v, const typename T::value_type& s)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v[i] - s;
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator-(const typename T::value_type& s, const T& v)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = s - v[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator-(const T& v1, const T& v2)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v1[i] - v2[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator*(const T& v, const typename T::value_type& s)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v[i] * s;
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator*(const typename T::value_type& s, const T& v)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = s * v[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator*(const T& v1, const T& v2)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v1[i] * v2[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator/(const T& v, const typename T::value_type& s)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v[i] / s;
    return result;
}

template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator/(const typename T::value_type& s, const T& v)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = s / v[i];
    return result;
}
template <typename T> static inline
std::enable_if_t<is_vector<T>::value, T>
operator/(const T& v1, const T& v2)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v1[i] / v2[i];
    return result;
}

template <typename T, typename U> static inline
std::enable_if_t<is_vector2<T>::value && is_vector2<U>::value, T> // incase mouse pos [uivec2 / vec2]
operator/(const T& v1, const U& v2)
{
    T result(uninitialize);
    for (unsigned int i = 0; i < T::size; i++)
        result[i] = v1[i] / static_cast<T::value_type>(v2[i]);
    return result;
}

// -- Logic operators --
template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, bool>
operator==(const T& v1, const T& v2)
{
    bool result = true;
    for (unsigned int i = 0; i < T::size; i++) {
        result &= almost_equals(v1[i], v2[i]);
    }
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, bool>
operator!=(const T& v1, const T& v2)
{
    return !(v1 == v2);
}

template <typename T> static inline
std::enable_if_t<std::is_integral<typename T::value_type>::value && is_vector<T>::value, bool>
operator==(const T& v1, const T& v2)
{
    bool result = true;
    for (unsigned int i = 0; i < T::size; i++) {
        result &= (v1[i] == v2[i]);
    }
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_integral<typename T::value_type>::value && is_vector<T>::value, bool>
operator!=(const T& v1, const T& v2)
{
    return !(v1 == v2);
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
lessThan(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] < y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
lessThanEqual(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] <= y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
greaterThan(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] > y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
greaterThanEqual(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] >= y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
equal(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] == y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_floating_point<typename T::value_type>::value && is_vector<T>::value, typename T::bool_type>
notEqual(const T& x, const T& y)
{
    typename T::bool_type result(uninitialize);
    for (unsigned int i = 0; i < T::size; ++i)
        result[i] = x[i] != y[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_same<typename T::value_type, bool>::value && is_vector<T>::value, bool>
any(const T& v)
{
    bool result = false;
    for (unsigned int i = 0; i < T::size; ++i)
        result = result || v[i];
    return result;
}

template <typename T> static inline
std::enable_if_t<std::is_same<typename T::value_type, bool>::value && is_vector<T>::value, bool>
all(const T& v)
{
    bool result = true;
    for (unsigned int i = 0; i < T::size; i++)
        result = result && v[i];
    return result;
}

// -- debug prints --
template <typename T> static inline
std::enable_if_t<is_vector<T>::value, std::ostream&>
operator<<(std::ostream& os, const T& v)
{
    os << "(";
    for (unsigned int i = 0; i < T::size; i++)
        os << v[i] << ((i < T::size - 1) ? ", " : ")");
    return os;
}


201
0
задан 16 марта 2018 в 07:03 Источник Поделиться
Комментарии
1 ответ

Повторный #ifdef/#else блоков может быть сведена к одному блоку, содержащее параллельные определения. Далее, определившись с фиксированной шириной подписал видах зависимым от платформы образом, мы можем использовать std::make_unsigned переносимым выводят остаток (при условии, что _MSC_VER компилятор реализует это правильно):

#ifdef _MSC_VER
using int64 = __int64;
using int64 = __int32;
using int64 = __int16;
using int64 = __int8;
#else
using int64 = std::int64_t;
using int32 = std::int32_t;
using int16 = std::int16_t;
using int8 = std::int8_t;
#endif

using uint64 = std::make_unsigned_t<int64>;
using uint32 = std::make_unsigned_t<int32>;
using uint16 = std::make_unsigned_t<int16>;
using uint8 = std::make_unsigned_t<int8>;

Думаю, что если вы хотите компиляции сбой в системах, которые не имеют точного 8/16/32/64-битные типы, или, действительно ли вы хотите std::int_fast64_t или std::int_least64_t (и семьи).


Мне пришлось сделать многочисленные исправления для кода ниже этой точки, чтобы даже скомпилировать - это не хватает много typename ключевые слова, к примеру, и gcc не нравится в классе typedefs (легко меняется на using, правда). И у вас есть целая куча анонимных структур, которые не разрешено в C++.


Здесь явная ошибка:

template <>
struct Types<4> {
using int_type = int;
using uint_type = unsigned int;
};

Я предполагаю, что вы хотели использовать новоявленной int32 и uint32 типы есть, а не машина-размера int и unsigned int.


static const bit_type bit_count = 8 * sizeof (value_type);

Где это 8 откуда? Это предположение CHAR_BIT? И почему она должна быть bit_type (чей размер зависит от T), а не просто std::size_t (как sizeof дает)?


explicit Float(const T& x) { value = x; }

Предпочитаю, чтобы инициализировать члены:

explicit Float(const T& x) : value{x}  {}


bool is_infinity()
{
return ((bit & ~sign_mask) == exponent_mask);
}

Это должно быть const:

bool is_infinity() const
{
return bit & ~sign_mask == exponent_mask;
}


union
{
value_type value;
bit_type bit;

struct {
bit_type fraction : fraction_count;
bit_type exponent : exponent_count;
bit_type sign : 1;
};
};

Порядок битовых полей в структуре определяется реализацией, так это совсем не портативный.


Некоторые повторения в печати можно избежать, используя простые функции форматирования:

#if PRINT_DEBUG_INFO
auto show_bool = [](std::ostream& os, const char *s, bool b) {
return os << std::setw(12) << std::left << s << " = "
<< std::setw(7) << b << '\n';
};
auto const saved_flags = std::cout.flags();

std::cout << "\n"
<< "distance = " << distance << '\n'
<< "diff = " << diff << '\n'
<< "sum = " << sum << '\n'
<< "min = " << std::numeric_limits<T>::min() << '\n'
<< "max = " << std::numeric_limits<T>::max() << '\n'
<< "---------------- \n"
<< std::boolalpha;
show_bool(std::cout, "under_flow", under_flow);
show_bool(std::cout, "over_flow", over_flow);
show_bool(std::cout, "diff sign", sign);
show_bool(std::cout, "inf", inff);
show_bool(std::cout, "nan", nan);
std::cout << "---------------- \n";
show_bool(std::cout, "assign", assign);
show_bool(std::cout, "ulp", ulp);
show_bool(std::cout, "fixed_epsilon", fixed_epsilon);
show_bool(std::cout, "relative_epsilon", relative_epsilon);
std::cout << '\n' << std::setfill('-') << std::setw(71) << ' ' << std::setfill(' ') << "\n\n";
std::cout.flags(saved_flags);
#endif

template <typename T> static inline std::ostream&
operator<<(std::ostream& os, const Float<T>& f)
{
auto show_dechexbin = [](std::ostream& os, char const *label, typename Float<T>::bit_type bits) {
return os << std::left << std::showbase
<< std::setw(8) << label << " = "
<< std::setw(10) << std::dec << bits << " : "
<< std::setw(10) << std::hex << bits << " : "
<< std::setw(32) << std::bitset<32>(bits) << "\n";
};
auto saved_flags = os.flags();

os << std::fixed << std::setprecision(25) << std::left;

os << "float = " << std::setw(10) << std::dec << f.data_float() << "\n";

show_dechexbin(os, "bits", f.data_bits());
show_dechexbin(os, "sign", f.sign_bits());
show_dechexbin(os, "exponent", f.exponent_bits());
show_dechexbin(os, "fraction", f.fraction_bits());
os.flags(saved_flags);
return os;
}


#include <cassert>

Не требуется


Этот клубок бросает все выглядит слишком страшно, чтобы рассмотреть. Например:

template <typename U>
Vec2(const Vec2<U>& v)
: x(static_cast<T>(v.x)), y(static_cast<T>(v.y)) {}

Если v.x и v.y не std::is_assignable для x и yпочему это должно быть разрешено неexplicit конструктор?

Вот еще что не делать то, что ожидается:

template <typename U>
Vec3 & operator*=(const Vec3<U>& v)
{
this->x *= static_cast<T>(v.x);
this->y *= static_cast<T>(v.y);
this->z *= static_cast<T>(v.z);
return *this;
}

Это не как векторное умножение строительство - векторное произведение может быть целесообразным для умножения-назначить, но вы также хотите, чтобы обеспечить дот-продукта функция.

Аналогично, операторы инкремента и декремента, которые заранее/ретард в (1,1,1) в направлении, кажется, не очень полезно. Вы могли бы аргументировать аргументы за увеличение/уменьшение масштаба, сохраняя неизменным направление, но я рекомендую просто не обеспечивают тех операторов.


Вот то, что делает противоположное тому, что он утверждает:

enum ctor { uninitialize };

T result(uninitialize);

Здесь result инициализируется. Название полностью вводит в заблуждение!


template <typename T> static inline
std::enable_if_t<std::is_same<typename T::value_type, bool>::value && is_vector<T>::value, bool>
all(const T& v)
{
bool result = true;
for (unsigned int i = 0; i < T::size; i++)
result = result && v[i];
return result;
}

Эта функция может просто вернуть результат std::all_of() если мы используем std::array в T вместо членов x, y, ...

На самом деле, большая часть реализации может быть уменьшена (и выше становится членом) если бы у нас было Vec<typename T, std::size_t N> как шаблон, а не индивидуальный Vec2, Vec3, ... классы.

5
ответ дан 16 марта 2018 в 10:03 Источник Поделиться