如何创建可变大小的c++数组与命名的公共成员,即x, y, z,…
How to create variable sized C++ array with named public members i.e. x, y, z, ...?
我正在寻找一种方法来创建一个通用的类似std的std::array< T, N >
,它已命名的成员元素,即x, y, z,…
是否有一种方法可以使用可变模板来构造这样的对象,以便通过模板形参有条件地定义成员?
对象通过operator[]
具有类似数组的访问是绝对重要的,而且它的内存占用不会因为额外的引用或指针而膨胀。
我考虑过模仿TR1的特征,但我真的不知道如何开始。
没有什么好实现的:
#include <cstddef>
template <std::size_t Extent>
struct Tuple;
// You cant not use a template for declaring member names.
// Hence a set of pre-declared tuples.
template <> struct Tuple<1> {
double x;
double operator [] (std::size_t idx) const { return x; }
};
template <> struct Tuple<2> {
double x;
double y;
double operator [] (std::size_t idx) const { return (idx < 1) ? x : y; }
};
template <> struct Tuple<3> {
double x;
double y;
double z;
double operator [] (std::size_t idx) const {
return (idx < 1)
? x
: (idx < 2)
? y
: z;
}
};
// However, you pay the price of conditional evaluation for accessing
// the members via operator [].
// An alternative is accessing the values through a std::array and member functions:
template <> struct Tuple<1> {
std::array<double, 1> data;
double x() const { return data[0]; }
double operator [] (std::size_t) const { return data[0]; }
};
template <> struct Tuple<2> {
std::array<double, 2> data;
double x() const { return data[0]; }
double y() const { return data[1]; }
double operator [] (std::size_t idx) const { return data[idx]; }
};
template <> struct Tuple<3> {
std::array<double, 3> data;
double x() const { return data[0]; }
double y() const { return data[1]; }
double z() const { return data[2]; }
double operator [] (std::size_t idx) const { return data[idx]; }
};
// However, now you have to write tuple.x(), which is annoying
// in mathematical equations.
对于完整性:另一个选项是通过联合进行类型双关语。但这是向未定义行为的阴暗面的移动(参见:对c++中类型双关语的看法?)。
我要在玩了一段时间后回答我自己的问题。我想我已经找到了我要找的东西,虽然这只是一个粗略的草图。我将把这个贴出来,以防其他人对类似的问题感到好奇。
定义: Tuple.hpp
#include <cassert>
#include <iostream>
namespace details
{
template<bool>
struct rule_is_greater_than_4;
template<>
struct rule_is_greater_than_4<true> {};
template<>
struct rule_is_greater_than_4<false> {};
template<class T, size_t N, size_t M>
class inner_storage : rule_is_greater_than_4< ( M > 4 )>
{
public:
T x, y, z, w;
private:
T more_data[ N - 4 ];
};
template<class T, size_t N>
class inner_storage<T, 2, N>
{
public:
T x, y;
};
template<class T, size_t N>
class inner_storage<T, 3, N>
{
public:
T x, y, z;
};
template<class T, size_t N>
class inner_storage<T, 4, N>
{
public:
T x, y, z, w;
};
}
template<class T, size_t N>
class Tuple : public details::inner_storage<T, N, N>
{
public:
static_assert( N > 1, "Size of 'n-tuple' must be > 1." );
// -- Constructors --
Tuple();
Tuple( T k );
Tuple( T x, T y );
Tuple( T x, T y, T z );
Tuple( T x, T y, T z, T w );
// -- Access operators --
const size_t size();
T &operator[]( const size_t i );
T const &operator[]( const size_t i ) const;
// -- Unary arithmetic operators --
Tuple<T, N> &operator=( Tuple<T, N> const &t );
friend std::ostream &operator<<( std::ostream &os, Tuple<T, N> &t );
};
// -- Unary operators --
template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t );
template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t );
// -- Binary arithmetic operators --
template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );
template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );
template<class T, size_t N>
Tuple<T, N> operator*( T const &s, Tuple<T, N> const &t2 );
template<class T, size_t N>
Tuple<T, N> operator*( Tuple<T, N> const &t1, T const &s );
template<class T, size_t N>
Tuple<T, N> operator/( Tuple<T, N> &t1, T const &s );
// -- Boolean operators --
template<class T, size_t N>
bool operator==( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );
template<class T, size_t N>
bool operator!=( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );
// -- Stream operator --
template<class T, size_t N>
inline std::ostream &operator<<( std::ostream &os, Tuple<T, N> const &t );
#include "Tuple.inl"
实现: Tuple.inl
// -- Constructors --
template <class T, size_t N>
Tuple<T, N>::Tuple()
{
}
template <class T, size_t N>
Tuple<T, N>::Tuple( T k )
{
for( size_t i = 0; i < N; i++ )
{
operator[]( i ) = k;
}
}
template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y )
{
static_assert( N == 2, "This constructor is resererved for 2-tuples." );
this->x = x;
this->y = y;
}
template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y, T z )
{
static_assert( N == 3, "This constructor is resererved for 3-tuples." );
this->x = x;
this->y = y;
this->z = z;
}
template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y, T z, T w )
{
static_assert( N == 4, "This constructor is resererved for 4-tuples." );
this->x = x;
this->y = y;
this->z = z;
this->w = w;
}
// -- Access operators --
template <class T, size_t N>
const size_t Tuple<T, N>::size()
{
return N;
}
template <class T, size_t N>
T &Tuple<T, N>::operator[]( const size_t i )
{
assert( i < N );
return ( &( this->x ) )[ i ];
}
template <class T, size_t N>
T const &Tuple<T, N>::operator[]( const size_t i ) const
{
assert( i < N );
return ( &( this->x ) )[ i ];
}
// -- Unary arithmetic operators --
template<class T, size_t N>
Tuple<T, N> &Tuple<T, N>::operator=( Tuple<T, N> const &t )
{
for( size_t i = 0; i < size(); i++ )
{
this->operator[]( i ) = t[ i ];
}
return *this;
}
// -- Unary operators --
template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t )
{
return t;
}
template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t )
{
return t * T( 0.0f );
}
// -- Binary operators --
template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{
Tuple<T, N> sum;
for( size_t i = 0; i < N; i++ )
{
sum[ i ] = t1[ i ] + t2[ i ];
}
return sum;
}
template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{
Tuple<T, N> difference;
for( size_t i = 0; i < N; i++ )
{
difference[ i ] = t1[ i ] - t2[ i ];
}
return difference;
}
template<class T, size_t N>
Tuple<T, N> operator*( Tuple<T, N> const &t, T const &s )
{
Tuple<T, N> product;
for( size_t i = 0; i < N; i++ )
{
product[ i ] = t[ i ] * s;
}
return product;
}
template<class T, size_t N>
Tuple<T, N> operator*( T const &s, Tuple<T, N> const &t )
{
Tuple<T, N> product;
for( size_t i = 0; i < N; i++ )
{
product[ i ] = s * t[ i ];
}
return product;
}
template<class T, size_t N>
Tuple<T, N> operator/( Tuple<T, N> const &t, T const &s )
{
assert( s != T( 0.0f ) );
Tuple<T, N> quotient;
T denom = T( 1.0f ) / s;
for( size_t i = 0; i < N; i++ )
{
quotient[ i ] = t[ i ] * denom;
}
return quotient;
}
// -- Boolean operators --
template<class T, size_t N>
bool operator==( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{
bool equal = true;
for( size_t i = 0; i < N; i++ )
{
equal = ( t1[ i ] == t2[ i ] ) ? equal : false;
}
return equal;
}
template<class T, size_t N>
bool operator!=( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{
return !( t1 == t2 );
}
// -- Stream operator --
template <class T, size_t N>
inline std::ostream &operator<<( std::ostream &os, Tuple<T, N> const &t )
{
os << "( ";
for( size_t i = 0; i < t.size(); i++ )
{
os << t[ i ];
if( i < t.size() - 1 )
{
os << ", ";
}
}
os << " )";
return os;
}
我不确定是否涵盖了所有的操作符重载,但我想简短一点。我也不满意构造函数的创建方式(也许可变模板可以拯救)。至少它给了我以下期望的功能:
typedef Tuple<float, 2> Vec2;
typedef Tuple<float, 4> Vec4;
typedef Tuple<float, 10> Vec10;
Vec2 a( 1.0 );
a.x = 3.0f;
a.y = -3.0f;
assert( a[ 1 ] == -3.0f ); // this works
// a.z = 1.0f; ------> compiler error
Vec10 b;
b.x = 0.0f; b.y = 1.0f; b.z = 2.0f; b.w = 3.0f;
b[ 5 ] = 12.0f;
// etc...
假设您想要存储int
的类型using mytype = int;
struct mytuple_ {
mytype x;
mytype y;
mytype z;
} tup;
这符合您的标准,不增加任何额外的内存使用,只是在内存中布局数据。
设置x=5
tup.x = 5;
相关文章:
- 是否可以将结构数组别名为结构成员数组?
- C++:初始化 constexpr 构造函数中的成员数组
- 使用带有参数包的数组的成员数组初始化类
- C++ 在析构函数调用之前删除的动态成员数组
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 指向具有不同大小的成员数组的指针
- 用另一个 constexpr 数组对成员数组进行大括号初始化
- 对象成员数组C++默认初始化
- 如何在构造函数中的类成员数组中分配数组值,而无需使用STD库
- 将类成员数组组合到单个数组时性能下降
- 如何将数据从公共方法添加到同一类中的私有成员数组中?
- 如何在C 中的派生类中分配数据成员数组
- C 集合构建器中类成员数组的2D数组大小
- 初始化不可复制、不可移动、显式构造类型的成员数组
- C 指针可以指向字符串文字的静态成员数组
- 成员数组位于何处
- 将对象成员数组与字符串进行比较
- 如何在 c++ 中从对象数组中获取数据成员数组
- 声明模板会员参考另一个类的模板成员数组
- C 初始化成员数组