C ++ 17 Limited type of bend expression to initialize a template class

Basically, I am trying to write my own game engine for practice and personal use (I know this is an almost impossible task, but, as I said, it is mainly for learning new things).

I am currently working on my math library (mainly vectors and matrices), and I came across an interesting, but mostly aesthetic problem.

The following pseudo-code is specified:

template <uint8 size>
struct TVector {
    float elements[size];
};

Now I want to be able to build a structure with the required number of floats as parameters:

TVector<3> vec0(1.0f, 2.5f, -4.0f); 
TVector<2> vec1(3.0f, -2.0f);

TVector<3> vec2(2.0f, 2.2f); // Error: arg missing 
TVector<2> vec3(1.0f, 2.0f, 3.0f) // Error: too many args

Since the size of the array is set by the template parameter, I struggled to declare a suitable constructor for the structure. My ultimate goal would be:

// This is pseudo-ideal-code
TVector(size * (float value)); // Create a constructor with number of size 
                               // parameters, which are all floats

, , , , 17- ++:

template<typename... Args>
    TVector(Args... values) {
        static_assert(sizeof...(values) <= size, "Too many args");
        uint8 i = 0;
        (... , void(elements[i++] = values));
    }

( ) , , , , , .

, , , .

, ?

, TVector:

template <const uint8 rows, const uint8 columns>
struct TMatrix {
    // elements[-columns-][-rows-]; 
    TVector<rows> elements[columns];
}

, fold , .

  • .

    TVector<2> vec(1.0f, 3.0f);
    TMatrix<2, 2> mat0(vec, vec); // Works
    TMatrix<2, 2> mat1(vec, {0.2f, -4.2f}); // Error
    // Does not compile, because the Type is not clear
    
  • (, , ).

  • .

TL; DR: , , :

, 3 , ?

- :

TVector(float... values) { 
// Maybe even specify the size of the pack with the size given in the struct template
    uint8 i = 0;
    (... , void(elements[i++] = values));
}

TMatrix(const TVector<rows>&... values) {
    uint8 i = 0;
    (..., void(elements[i++] = values));
}

, , , , , .


, :)

+4
2

, , ( ).

:: initializer_list:

:

  • :

    // Constructors:
    TVector(std::initalizer_list<float> values);
    TMatrix(std::initalizer_list<TVector<rows>> values);
    
  • :

    TVector<3>    vec { 1.0f, 0.0f, 2.0f };
    TMatrix<3, 3> mat { vec, { 3.0f, 4.0f, 1.0f }, vec };
    

:


::

:

  • :

    // Constructors:
    TVector(std::array<float, size>&& values);
    TMatrix(std::aray<TVector<rows>, columns>&& values);
    
  • ,

:

  • .

    TVector<3>    vec { { 1.0f, 0.0f, 2.0f } };
    TMatrix<3, 3> mat { vec, TVector<3>{ { 3.0f, 4.0f, 1.0f } }, vec };
    

Fold expression -

:

  • TVector<3>    vec { 1.0f, 0.0f, 2.0f };
    TMatrix<3, 3> mat { vec, TVector<3>{ 3.0f, 4.0f, 1.0f }, vec };
    

:

  • ( )

    // Constructors:
    template<typename... Args, std::enable_if_t<
        is_pack_convertible<float, Args...>::value && 
        is_pack_size_of<columns, Args...>::value, bool> = false >
    TVector(std::array<float, size>&& values);
    
    template<typename... Args, std::enable_if_t<
        is_pack_convertible<Vector<rows>, Args...>::value && 
        is_pack_size_of<columns, Args...>::value, bool> = false >
    TMatrix(std::aray<TVector<rows>, columns>&& values);
    

is_pack_convertible/is_pack_size_of

// Declaration - checks if all types of a pack are convertible to one type
template <typename To, typename... Pack> struct is_pack_convertible;
// End of pack case
template <typename To> struct is_pack_convertible<To> : std::true_type {};
// Recursive bool &&
template <typename To, typename From, typename... Pack>
struct is_pack_convertible<To, From, Pack...> {
    static constexpr bool value = std::is_convertible<From, To>::value
        && is_pack_convertible<To, Pack...>::value;
};

// Declaration - checks if the pack is equal to a certain size
template <size_t size, typename... Pack> struct is_pack_size_of;
// End of pack: size is equal
template <> struct is_pack_size_of<0> : std::true_type {};
// End of pack: size is not equal
template <size_t remainder> struct is_pack_size_of<remainder> : std::false_type {};
// Count down size for every element in pack
template <size_t size, typename Arg, typename... Pack> 
struct is_pack_size_of<size, Arg, Pack...> {
    static constexpr bool value = is_pack_size_of<size - 1, Pack...>::value;
};

, .

0

- :

template <typename Seq> struct TVectorImpl;

template <std::size_t, typename T> using force_type = T;

template <std::size_t ... Is>
struct TVectorImpl<std::index_sequence<Is...>>
{
    TVectorImpl(force_type<Is, float>... args) : elements{args...} {}

    float elements[sizeof...(Is)];
};

template <std::size_t size>
using TVector = TVectorImpl<decltype(std::make_index_sequence<size>())>;

( {2.4, 5}).

, ++ 14 ( index_sequence ++ 11).

+1

Source: https://habr.com/ru/post/1692274/


All Articles