由于阅读了很多警告不要使用这样的工会:
union rgba
{
struct
{
uint8_t r, g, b, a;
} components;
uint8_t index[4];
uint32_t value;
};因为这是未定义的行为,所以我决定保持简单,如下所示:
struct rgba
{
uint8_t r, g, b, a;
};但是,有时我确实需要使用索引在一个循环中访问r、g、b和a,否则我必须分别为每个组件复制相当长的代码。
所以我想出了这个:
struct rgba
{
u8 r, g, b, a;
constexpr u8& operator[](size_t x)
{
return const_cast<u8*>(&r)[x];
}
};这依赖于这样的假设:r、g、b和a以线性方式放置在内存中,中间没有隐藏的样板,编译器保留可变顺序。
这样,我就可以像我想要的那样访问组件:
rgba c;
for (int i = 0; i < 3; i++)
c[i] = i ^ (i + 7);
c.a = 0xFF;c.r() = 5,因为它看起来很有趣。c.components[RED]这样的访问器使用宏,我喜欢避免宏。c.components[Image::Channels::Red]。
发布于 2015-08-15 10:44:33
标准给出了关于问题1的答案:
9.2/15:分配具有相同访问控制的类的非静态数据成员,以便以后的成员在类对象中具有更高的地址。具有双ff访问控制的非静态数据成员的分配顺序是fi编辑的。实现对齐需求可能导致两个相邻的成员不能在彼此之后立即分配;也可能需要管理虚拟函数和虚拟基类的空间。
问题2的答案有很多种选择。如果您喜欢数组表示法:
switch()来安全地返回对正确元素的引用。第一个看起来应该是:
struct rgba2
{
uint8_t r, g, b, a;
constexpr uint8_t& operator[](size_t x)
{
assert(x>=0 && x<4);
switch (x){
case 0: return r;
case 1: return g;
case 2: return b;
case 3: return a;
//default: throw(1); // not possible with constexpr
}
}
};第二项是:
struct rgba3
{
enum ergb { red, green, blue, alpha};
uint8_t c[alpha+1];
constexpr uint8_t& operator[](ergb x)
{
assert(x>=0 && x<4);
return c[x];
}
};发布于 2015-08-15 11:37:01
您可以通过使用指向成员的指针的静态数组,以符合标准的方式高效地完成这一任务。
内存开销是每个类一个数组。在优化的构建中,当索引在编译时已知时,生成的代码与直接成员访问相同。
下面是一些示例代码(来源):
#include <iostream>
template<class T>
class Vector3
{
public:
Vector3(const T &xx, const T &yy, const T &zz) :
x(xx), y(yy), z(zz)
{
};
T& operator[](size_t idx)
{
return this->*offsets_[idx];
};
const T& operator[](size_t idx) const
{
return this->*offsets_[idx];
};
public:
T x,y,z;
private:
static T Vector3::* const offsets_[3];
};
template<class T>
T Vector3<T>::* const Vector3<T>::offsets_[3] =
{
&Vector3<T>::x,
&Vector3<T>::y,
&Vector3<T>::z
};
int main()
{
Vector3<float> vec(1,2,3);
vec[0] = 5;
std::cout << vec.x << std::endl;
}https://stackoverflow.com/questions/32023374
复制相似问题