c++中同一变量的多个名称

Multiple names for the same variable in C++

本文关键字:变量 c++      更新时间:2023-10-16

是否有可能在c++中使用不同的名称而不使用预处理器来引用相同的变量?

要达到与伪代码

相同的效果
struct vec3f {
    float[3] values;
};
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]) { }
};

是否有一种方法可以在不增加结构体大小的情况下获得此编译时名称替换?

这个怎么样?

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

我不确定您是否想在这种情况下使用继承。您最好使用普通的旧式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 );

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

的想法是,你给类命名的变量顺序,然后也有一个static const成员的指针到成员类型的数组。operator[]被重载以查找合适的成员指针,使用它从this中选择成员,并返回一个引用。

之所以有效,是因为指向成员的指针不是普通指针;它们比这更神奇。(这就是为什么您可以创建指向成员函数的非绑定指针,以及为什么它们不能用于期望使用普通函数指针的地方)。

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

替代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

如果您可以验证vec3fvec3c的内存布局在您的平台和操作系统上是相同的…考虑到填充/对齐等…你可以做

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