Constant integer bar in simple class

Given the following simple declaration, is it possible to give the class an integer constant that defines the number of components (in this case, 2)? Vec3 and Vec4 will have 3 and 4 respectively. I just want it as a compile time constant for instantiating other templates in various ways. It doesn't have to be at runtime.

template<class T>
struct Vec2
{ 
    typedef T value_type;
    typedef unsigned index_type;

    struct 
    {
        T x, y; 
    };
};

      

+3


source to share


3 answers


The most portable way is to add an enum constant:

template<class T> struct Vec2
{
    enum { num_components = 2 };
};
template<class T> struct Vec3
{
    enum { num_components = 3 };
};

      



Then just use V::num_components

if necessary.

If you are in C ++ 11 you can also use static const int num_components = 2;

instead of anonymous enum

, but if you need compatibility with older compilers then the idiom will enum

save you some headaches.

+2


source


The decision would indicate that politicians do exactly that

// base class to store members
template<size_t N>
struct Coords; 

template<>
struct Coords<2> {
    double x, y; 
}; 

template<>
struct Coords<3> {
    double x, y, z; 
}; 

template<>
struct Coords<4> {
    double x, y, z, w; 
}; 

// members depend on your base class
template<class T, size_t N>
struct Vec : Coords<N>
{
    using num = integral_constant<size_t, N>; 
};

      

Now, for each type, the following exists (note which is a type, so it doesn't take up any space ): num

Vec<2> -> x, y        and   num::value = 2 (`constexpr` - compile time usable)        
Vec<3> -> x, y, z     and   num::value = 3              //  
Vec<4> -> x, y, z, w  and   num::value = 4              //

      



If you don't want the style of named members , I would suggest using a meber containing all values, like

double _coords[N]; // N is a compile time constant so you can have arrays

      

because such a solution would be more scalable, general, and easier to code.

PS I am using double

instead T

to simplify the examples.

+2


source


There are already two solutions to this problem in the standard library.

std::array<type, size>

is a fixed-size array of one type that has a size () member function, start and end iterators, plus the [] operator.

std::tuple<types...>

gives a vector of disjoint types that can be indexed by index: get<i>(tuple)

or type get<typename>(tuple)

.

edit:

here's one possible solution:

#include <iostream>
#include <type_traits>
#include <utility>
#include <array>

template<class Type, size_t Size>
struct my_vector
{
    static constexpr size_t num_components = Size;

    template<class...Args, typename = std::enable_if_t< (sizeof...(Args) == Size) > >
    my_vector(Args&&...args) : _data { std::forward<Args>(args)... } {}

    template<size_t I >
    Type get() const {
        return _data[I];
    }

    std::array<Type, Size> _data;
};

template<class Type, size_t Size, size_t I, class VectorType = my_vector<Type, Size>, typename = void>
struct get;
template<class Type, size_t Size, size_t I >
struct get<Type, Size, I, my_vector<Type, Size>, std::enable_if_t<I <= Size> >
{
static Type apply(const my_vector<Type, Size>& v) {
        return v.get<I>();
    }
};

template<class Type, size_t Size>
Type x(const my_vector<Type, Size>& v)
{
    return get<Type, Size, 0, my_vector<Type, Size>>::apply(v);
}

template<class Type, size_t Size>
Type y(const my_vector<Type, Size>& v)
{
    return get<Type, Size, 1, my_vector<Type, Size>>::apply(v);
}

template<class Type, size_t Size>
Type z(const my_vector<Type, Size>& v)
{
    return get<Type, Size, 2, my_vector<Type, Size>>::apply(v);
}

template<size_t I, class Type, size_t Size>
Type more(const my_vector<Type, Size>& v)
{
    return get<Type, Size, I+3, my_vector<Type, Size>>::apply(v);
}


template<class T> using Vec2 = my_vector<T, 2>;
template<class T> using Vec3 = my_vector<T, 3>;
template<class T> using Vec6 = my_vector<T, 6>;

using namespace std;

auto main() -> int
{
    Vec2<int> v2 { 1, 2 };
    Vec3<int> v3 { 1, 2, 3 };
    Vec6<int> v6 { 1, 2, 3, 4, 5, 6 };

    cout << "v2: " << x(v2) << ", " << y(v2) << endl;
    cout << "v3: " << x(v3) << ", " << y(v3) << ", " << z(v3) << endl;
    cout << "v6: "
    << x(v6) << ", " << y(v6) << ", " << z(v6) << ", "
    << more<0>(v6) << ", " << more<1>(v6) << ", " << more<2>(v6)
    << endl;

    return 0;
}

      

expected output:

v2: 1, 2
v3: 1, 2, 3
v6: 1, 2, 3, 4, 5, 6

      

+1


source







All Articles