Несколько имен для одной и той же переменной в C ++ - PullRequest
5 голосов
/ 30 декабря 2011

Возможно ли в 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]) { }
};

Есть ли способ получить подстановку имен во время компиляции без увеличения размера структуры?

Ответы [ 4 ]

10 голосов
/ 30 декабря 2011

Как насчет этого?

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 голосов
/ 30 декабря 2011

Я не уверен, что вы хотите использовать наследование в этом случае. Вы могли бы быть лучше с простым старым 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 голос
/ 30 декабря 2011

Как это случилось, я впервые увидел действительно изящный трюк для этого несколько лет назад.

Идея состоит в том, что вы присваиваете классу именованные переменные по порядку, а затем также получаете static const член типа массив-указатель-на-член. operator[] перегружен для поиска соответствующего указателя на член, используйте его для выбора члена из this и возврата ссылки.

Это работает, потому что указатели на члены не являются обычными указателями; они немного более волшебны, чем это. (Это то, что позволяет создавать неограниченные указатели на функции-члены и почему их нельзя использовать там, где ожидаются простые указатели на функции).

Это также означает, что вам не нужно использовать какие-либо приемы приведения, полагаться на какие-либо виды выравнивания, непереносимое поведение анонимного объединения или гарантии расположения памяти, и вы все равно можете ссылаться на компоненты структуры как именованные поля, а не через функции доступа.

1 голос
/ 30 декабря 2011

АЛЬТЕРНАТИВА 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;    
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...