c++ - 像数组一样访问成员?

标签 c++ c++11 strict-aliasing type-punning

由于阅读了很多不要使用这样的 union 的警告:

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;
};

但碰巧有时我确实需要访问 rgba在使用索引的循环中,否则我必须分别为每个组件复制相当长的代码。

所以我想出了这个:

struct rgba
{
    u8 r, g, b, a;

    constexpr u8& operator[](size_t x)
    {
        return const_cast<u8*>(&r)[x];
    }
};

这依赖于以下假设:rgba 以线性方式放置在内存,中间没有隐藏的样板,并且编译器保留变量顺序。

有了这个,我就可以按照我想要的方式访问组件:

rgba c;
for (int i = 0; i < 3; i++)
    c[i] = i ^ (i + 7);
c.a = 0xFF;
  1. 由于我做了相当大的假设,我很确定这比使用 union 进行类型双关更加未定义的行为。我说得对吗?
  2. 我还能如何实现类似的设计?
    1. 如果可能的话,我希望避免编写 c.r() = 5,因为它看起来很有趣。
    2. 拥有诸如 c.components[RED] 之类的访问器会使用宏,而我喜欢避免使用宏。
    3. 当考虑到访问此类枚举所需的命名空间时,用枚举替换第 2 点中的宏看起来会很难看。想象一下c.components[Image::Channels::Red]

最佳答案

标准给出了问题1的答案:

9.2/15: Nonstatic data members of a class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes.

问题 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];
    }
};

live demo

关于c++ - 像数组一样访问成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32023374/

相关文章:

c++ - Qt 使用自定义图标创建快捷方式

c++ - 编译包装器时出现 SWIG [C++ to Lisp(CFFI)] 错误

c++ - 实例化和删除对象 C++

c++ - 自定义迭代器的 cbegin 未被使用

c++ - 启动多个线程,只等待一个线程结束获取结果

c++ - thread.join() 超时

c - 为什么转换不同的指针类型会导致 TBAA(基于类型的别名分析)违规?

c++ - 严格指针别名 : is access through a 'volatile' pointer/reference a solution?

c++ - 通过引用访问是否违反了严格的别名规则?

c++ - 关闭或最小化 cmd 窗口