你能创建一个包含数组成员的结构体,其中每个数组元素也有一个名称吗?

问题描述 投票:0回答:4

在 C++ 中是否可以在不使用预处理器的情况下使用不同的名称引用同一变量?

达到与此伪代码相同的效果

struct vec3f {
    float values[3];
};

struct color : public vec3f {
    #define r values[0]
    #define g values[1]
    #define b values[2]
};

color c;
c.r = 0.5f;

以下内容具有正确的语义,只是它在结构中为 3 个引用分配了空间:

struct color : public vec3f {
    float& r;
    float& g;
    float& b;
    color() : r(values[0]), g(values[1]), b(values[2]) { }
};

有没有办法在不增加结构体大小的情况下进行编译时名称替换?

c++ reference variable-assignment
4个回答
10
投票

这个怎么样?

struct vec3f {
    float[3] values;
};

struct color : public vec3f
{
    float& r() { return values[0]; }
    float& g() { return values[1]; }
    float& b() { return values[2]; }
    const float& r() const { return values[0]; }
    const float& g() const { return values[1]; }
    const float& b() const { return values[2]; }
};

1
投票

我不确定您是否想在这种情况下使用继承。您可能更适合使用普通的旧

union
类型:

typedef float vec3f[3];
union color {
   vec3f values;
   struct {
      float r;
      float g;
      float b;
   };
};

color c;
c.values[0] = 10;
assert( c.r == 10 );

1
投票

碰巧的是,几年前我第一次看到一个非常巧妙的技巧

这个想法是,你按顺序给类命名变量,然后还有一个

static const
成员指针数组类型的成员。
operator[]
被重载以查找适当的指向成员的指针,使用它从
this
中选择成员,并返回引用。

这是可行的,因为指向成员的指针不是普通的指针;它们比那更神奇一点。 (这就是使您能够创建指向成员函数的未绑定指针的原因,也是为什么它们不能在需要普通函数指针的地方使用的原因)。

这也意味着您不必使用任何转换技巧,依赖于任何类型的对齐、不可移植的匿名联合行为或内存布局保证,并且您仍然可以引用结构的组件作为命名字段而不是通过访问器函数。


1
投票

替代方案1

当您需要变量别名时,总是创建一个临时变量。有了好的优化器,您几乎看不到任何性能差异。

struct vec3f
{
    float values[3];
};

struct tempvec
{
    float &r;
    float &g;
    float &b;

    tempvec( vec3f& bar )
        :r(bar.values[0]) 
        , g(bar.values[1]) 
        , b(bar.values[2]){}
};

int main() 
{
    vec3f temp;
    temp.values[0] = 2.40f;

    //when you want to alias values[0] as r do this
    tempvec(temp).r = 42;
    tempvec(temp).g = 42;

    return 0;    
}

替代方案2

如果您可以验证

vec3f
vec3c
的内存布局在您的平台和操作系统上是否相同..考虑到 填充/对齐等...您可以这样做

struct vec3f
{
    float values[3];
};

struct vec3c
{
    float r,g,b;
};

int main() 
{
    vec3f temp;
    temp.values[0] = 2.40f;

    vec3c* alias  = reinterpret_cast<vec3c*>(&temp);

    alias->r = 4.2f;
    alias->g = 4.2f;
    alias->b = 4.2f;

    return 0;    
}
© www.soinside.com 2019 - 2024. All rights reserved.