简单类

时间:2015-06-30 20:40:08

标签: c++ typetraits

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

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

    struct 
    {
        T x, y; 
    };
};

3 个答案:

答案 0 :(得分:2)

解决方案可让您指定策略来完全执行

// 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是一种类型,因此它不占用任何空间):

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

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

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

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

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

答案 1 :(得分:2)

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

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成语将会保存你有些头疼。

答案 2 :(得分:1)

标准库中已有两种解决此问题的方法。

std::array<type, size>是一个固定大小的数组,有一个size()成员函数,begin和end迭代器以及一个[]运算符。

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