简单 class 中的常数整数特征

Constant integer trait in simple class

给定下面的简单声明,是否可以给 class 一个常量整数特征来指定组件的数量(在本例中为 2)? Vec3 和 Vec4 分别有 3 和 4。我只想将其作为编译时常量,以各种方式实例化其他模板。它不必在运行时存在。

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

    struct 
    {
        T x, y; 
    };
};

标准库中已经有两个解决这个问题的方法。

std::array<type, size> 是一种类型的固定大小数组,它具有一个 size() 成员函数、开始和结束迭代器以及一个 [] 运算符。

std::tuple<types...> 给出可以通过索引索引的不相交类型的向量:get<i>(tuple) 或类型 get<typename>(tuple).

编辑:

这是一种可能的解决方案:

#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;
}

预期输出:

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

一种解决方案是让您指定 政策 来做到这一点

// 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>; 
};

现在每种类型都存在以下内容(请注意 num 是一种类型,因此它不占用任何 space):

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              //

除非您特别想要 命名成员样式 我建议使用包含所有值的成员,例如

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

因为这样的解决方案更具可扩展性、通用性并且更易于编码。

PS 我使用 double 代替 T 来简化示例。

最便携的方法是添加枚举常量:

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

然后在需要的地方使用V::num_components

如果你喜欢 C++11,那么你也可以使用 static const int num_components = 2; 而不是匿名的 enum,但如果你需要与旧编译器兼容,那么 enum 习惯用法会让你省去一些麻烦。