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