C++ 使用可变模板(或其他解决方案)有效地对数据施加结构

C++ 使用可变模板(或其他解决方案)有效地对数据施加结构,c++,c++11,C++,C++11,在我的项目中,我正在处理大量使用浮点数的3d数学(例如方阵和向量长度为4)。当然,我已经创建了一些类来帮助我,因为我使用了一个数组作为成员的数据类型,我知道它们将被不断地分配。没有虚拟对象,所以没有v-table指针,所以没有RTTI,但我有一个断言可以警告我 现在我有一些类似的东西:(这是伪代码,显示了什么是有效的,但为了简洁起见,没有细节) 如果我能处理浮点数的缓冲,速度会快得多。(在上面的例子中,是7个浮点数,而不是内存中可能不连续的2个变量) 现在在C++11中,您有了比以前更强大的元编

在我的项目中,我正在处理大量使用浮点数的3d数学(例如方阵和向量长度为4)。当然,我已经创建了一些类来帮助我,因为我使用了一个数组作为成员的数据类型,我知道它们将被不断地分配。没有虚拟对象,所以没有v-table指针,所以没有RTTI,但我有一个断言可以警告我

现在我有一些类似的东西:(这是伪代码,显示了什么是有效的,但为了简洁起见,没有细节)

如果我能处理浮点数的缓冲,速度会快得多。(在上面的例子中,是7个浮点数,而不是内存中可能不连续的2个变量)

现在在C++11中,您有了比以前更强大的元编程,使用与元组相同的逻辑,我想要一个类,我可以这样使用:

data_buffer<Mat4x4,Vec4,Vec3> variables;
data\u缓冲变量;
说。然后(最坏情况)访问:
variables.get()*variables.get()

但它不是一个元组!编译器不能填充这些,它必须对浮点数组施加结构。例如,
start\u of_floats+4
是上述示例中颜色向量的开始。它可以将此强制转换返回到
Vec3&

“较低”(远离代码结构)的优化将确保这样的解决方案是有效的(至少在GCC中是有效的),因此从性能角度来看,这是很好的

我不确定如何使用模板执行此操作,缓冲区指针的偏移量将来自模板参数,但我不确定如何将Ts的sizeofs之和计算到模板中的某个点

加分
任何你可以添加、更改或做的事情都可以让它变得更好。我想使用对象,这是一个实践/实验,在过去我使用了大量的宏,没有对象(在C中)来做这件事。我希望有一个更好的方式,没有性能的惩罚

如果我没弄错的话,我会从这样的设计开始:

template<typename ElType, std::size_t N>
class SubArray
{
public:
    typedef ElType value_type;
    typedef ElType* iterator;
    typedef const ElType* const_iterator;
    typedef ElType& reference;
    typedef const ElType& const_reference;
    typedef typename std::iterator_traits<ElType*>::size_type size_type;
    typedef typename std::iteartor_traits<ElType*>::difference_type difference_type;

    explicit SubArray(ElType* ptr);

    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;
    static constexpr size_type size() const;

    reference operator[](size_type i);
    const_reference operator[](size_type i) const;

private:
    ElType* m_start;
};

template<typename T> class ArrayUserWithStorage;

template<typename ElType, std::size_t N>
class ArrayUser
{
protected:
    typedef ElType element_type;
    static constexpr std::size_t elements();

    explicit ArrayUser(SubArray<ElType, N>);

    SubArray<ElType, N>& storage();
    const SubArray<ElType, N>& storage() const;

private:
    SubArray<ElType, N> m_storage;

    template <typename T>
    friend class ArrayUserWithStorage<T>;
};

template <typename T>
struct ArrayUserWithStorage :
    private std::array<typename T::element_type, T::elements()>,
    public ArrayUser<typename T::element_type, T::elements()>
{
public:
    template <typename... Args>
    ArrayUserWithStorage(Args&& ... args) :
        std::array(),
        T(ArrayUser<typename T::element_type, T::elements()>(data()),
          std::forward<Args>(args)...)
    {}
};

class Vec3 : public ArrayUser<float, 3>
{
public:
    explicit Vec3(SubArray<float, 3> storg);
    Vec3(SubArray<float, 3> storg, float x, float y, float z) :
        ArrayUser(storg)
    {
        storage()[0] = x;
        storage()[1] = y;
        storage()[2] = z;
    }

    // ...
};

typedef ArrayUserWithStorage<Vec3> LoneVec3;

template <typename ElType, typename... Ts>
class ArrayAsTuple
{
    template <std::size_t NToAdd, typename... Us>
    struct offset_helper

    template <std::size_t Sum, typename... Us>
    struct offset_helper<0, Us...>
    {
        static constexpr std::size_t offset = 0;
    };

    template <std::size_t NToAdd, typename U1, typename... Us>
    struct offset_helper<NToAdd, U1, Us...>
    {
        static_assert(std::is_same<typename U1::element_type, ElType>::value,
                      "Mismatch in ArrayUser element types");
        static constexpr std::size_t offset =
            U1::elements() + offset_helper<NToAdd-1, Us...>::offset;
    };

    static constexpr total_elements = offset_helper<sizeof...(Ts), Ts...>::offset;

    template <std::size_t I, typename... Us>
    struct nth_type;

    template <typename U1, typename... Us>
    struct nth_type<0, U1, Us...>
    { typedef U1 type; };

    template <std::size_t I, typename U1, typename... Us>
    struct nth_type<I, U1, Us...>
    { typedef typename nth_type<I-1, Us...>::type type; };

    std::array<ElType, total_elements> m_storage;

public:
    using array_type = std::array<ElType, total_elements>;

    ArrayAsTuple();

    array_type& arr() &;
    const array_type& arr() const &;

    template<std::size_t N>
    nth_type<N, Ts...> get() &;
    { return nth_type<N, Ts...>( m_storage.data() + offset_helper<N, Ts...>::offset ); }
};
模板
类子阵
{
公众:
typedef ElType value_type;
typedef ElType*迭代器;
typedef常量ElType*常量迭代器;
typedef ElType&reference;
typedef const ElType和const_参考;
typedef typename std::迭代器\特征::大小\类型大小\类型;
typedef typename std::iteartor_traits::difference_type difference_type;
显式子阵(ElType*ptr);
迭代器begin();
迭代器end();
常量迭代器begin()常量;
常量迭代器end()常量;
静态constexpr size_type size()常量;
参考运算符[](i型尺寸);
常量参考运算符[](大小类型i)常量;
私人:
ElType*m_开始;
};
模板类ArrayUserWithStorage;
模板
ArrayUser类
{
受保护的:
typedef ElType元素\ u类型;
静态constexpr std::size_t elements();
显式阵列(子阵);
子阵列&存储();
常量子数组和存储()常量;
私人:
子阵m_存储;
模板
朋友级阵列存储;
};
模板
结构ArrayUserWithStorage:
私有std::数组,
公共传讯员
{
公众:
模板
阵列存储(Args&…Args):
std::array(),
T(ArrayUser(data()),
标准::转发(args)
{}
};
Vec3类:公共阵列用户
{
公众:
显式Vec3(子阵存储);
Vec3(子阵列存储、浮点x、浮点y、浮点z):
ArrayUser(斯托格)
{
存储()[0]=x;
存储()[1]=y;
存储()[2]=z;
}
// ...
};
带存储LoneVec3的类型DEF阵列服务器;
模板
类数组元组
{
模板
结构偏移量辅助对象
模板
结构偏移量辅助对象
{
静态constexpr std::size\u t offset=0;
};
模板
结构偏移量辅助对象
{
静态断言(std::is_same::value,
“ArrayUser元素类型不匹配”);
静态constexpr std::大小\u t偏移量=
U1::elements()+offset\u helper::offset;
};
静态constexpr total_elements=offset_helper::offset;
模板
结构n_型;
模板
结构n_类型
{typedef U1 type;};
模板
结构n_类型
{typedef typename n_type::type type type;};
std::阵列m_存储;
公众:
使用array_type=std::array;
ArrayAsTuple();
数组类型&arr()&;
常量数组类型&arr()常量&;
模板
n_类型get()&;
{返回第n个类型(m_storage.data()+offset_helper::offset);}
};

那么您希望将更漂亮的视图放入
float
s的原始缓冲区?
data_buffer<Mat4x4,Vec4,Vec3> variables;
template<typename ElType, std::size_t N>
class SubArray
{
public:
    typedef ElType value_type;
    typedef ElType* iterator;
    typedef const ElType* const_iterator;
    typedef ElType& reference;
    typedef const ElType& const_reference;
    typedef typename std::iterator_traits<ElType*>::size_type size_type;
    typedef typename std::iteartor_traits<ElType*>::difference_type difference_type;

    explicit SubArray(ElType* ptr);

    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;
    static constexpr size_type size() const;

    reference operator[](size_type i);
    const_reference operator[](size_type i) const;

private:
    ElType* m_start;
};

template<typename T> class ArrayUserWithStorage;

template<typename ElType, std::size_t N>
class ArrayUser
{
protected:
    typedef ElType element_type;
    static constexpr std::size_t elements();

    explicit ArrayUser(SubArray<ElType, N>);

    SubArray<ElType, N>& storage();
    const SubArray<ElType, N>& storage() const;

private:
    SubArray<ElType, N> m_storage;

    template <typename T>
    friend class ArrayUserWithStorage<T>;
};

template <typename T>
struct ArrayUserWithStorage :
    private std::array<typename T::element_type, T::elements()>,
    public ArrayUser<typename T::element_type, T::elements()>
{
public:
    template <typename... Args>
    ArrayUserWithStorage(Args&& ... args) :
        std::array(),
        T(ArrayUser<typename T::element_type, T::elements()>(data()),
          std::forward<Args>(args)...)
    {}
};

class Vec3 : public ArrayUser<float, 3>
{
public:
    explicit Vec3(SubArray<float, 3> storg);
    Vec3(SubArray<float, 3> storg, float x, float y, float z) :
        ArrayUser(storg)
    {
        storage()[0] = x;
        storage()[1] = y;
        storage()[2] = z;
    }

    // ...
};

typedef ArrayUserWithStorage<Vec3> LoneVec3;

template <typename ElType, typename... Ts>
class ArrayAsTuple
{
    template <std::size_t NToAdd, typename... Us>
    struct offset_helper

    template <std::size_t Sum, typename... Us>
    struct offset_helper<0, Us...>
    {
        static constexpr std::size_t offset = 0;
    };

    template <std::size_t NToAdd, typename U1, typename... Us>
    struct offset_helper<NToAdd, U1, Us...>
    {
        static_assert(std::is_same<typename U1::element_type, ElType>::value,
                      "Mismatch in ArrayUser element types");
        static constexpr std::size_t offset =
            U1::elements() + offset_helper<NToAdd-1, Us...>::offset;
    };

    static constexpr total_elements = offset_helper<sizeof...(Ts), Ts...>::offset;

    template <std::size_t I, typename... Us>
    struct nth_type;

    template <typename U1, typename... Us>
    struct nth_type<0, U1, Us...>
    { typedef U1 type; };

    template <std::size_t I, typename U1, typename... Us>
    struct nth_type<I, U1, Us...>
    { typedef typename nth_type<I-1, Us...>::type type; };

    std::array<ElType, total_elements> m_storage;

public:
    using array_type = std::array<ElType, total_elements>;

    ArrayAsTuple();

    array_type& arr() &;
    const array_type& arr() const &;

    template<std::size_t N>
    nth_type<N, Ts...> get() &;
    { return nth_type<N, Ts...>( m_storage.data() + offset_helper<N, Ts...>::offset ); }
};