【问题标题】:Multiple names for the same variable in C++C++中同一个变量的多个名称
【发布时间】:2012-01-30 06:23:43
【问题描述】:

在 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]) { }
};

有没有办法在不增加结构大小的情况下获得这种编译时名称替换?

【问题讨论】:

    标签: c++ reference variable-assignment


    【解决方案1】:

    这个怎么样?

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

    【讨论】:

    • 我试图避开括号,但这绝对是正确的做法。
    【解决方案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 );
    

    【讨论】:

    • 我认为那一定是c.values.values[0] 很遗憾:(
    • @MooingDuck: ?? vec3f 类型是 typedef,而不是原始的 struct,并且代码是正确的。 c.values.values[0] 将是编译器错误。
    • 哇,没注意到 typedef。
    • 不幸的是,这是未定义的行为,因为数组不参与“公共初始子序列”规则,允许通过与写入不同的成员读取联合。
    【解决方案3】:

    碰巧,几年前我第一次看到一个非常整洁的trick for this

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

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

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

    【讨论】:

    • 虽然是一个巧妙的技巧,但当 color 应该是 vec3f 时,我看不出这有什么帮助。
    • @MooingDuck 如果我们要做一些奇怪的事情,比如将颜色视为向量,我几乎看不出继承的方向是什么,甚至存在继承......所以你'd 用重载的 operator[]r/g/b 成员创建一个 color,然后 typedef vec3f 给它。
    【解决方案4】:

    备选方案 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 的内存布局在您的平台和操作系统上是否相同.. 考虑到padding/alignment 等...您可以这样做

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

    【讨论】:

    • 你的替代方案 2 让我发现了 cast 运算符,所以 color 可以写成 struct color { float r, g, b; operator vec3f&amp;() { return *((vec3f*)this); };
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2014-01-12
    相关资源
    最近更新 更多