2011-12-29 26 views
5

Возможно ли, что на C++ ссылаться на одну и ту же переменную, используя разные имена, без использования препроцессора?Несколько имен для одной и той же переменной в 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]) { } 
}; 

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

ответ

9

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

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

Я пытался избежать скобок, но это, безусловно, правильный способ сделать это. – wjd

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); 
+0

Я думаю, что это должно быть 'c.values.values ​​[0]' sadly :( –

+1

@MooingDuck: ?? Тип 'vec3f' - это * typedef *, а не оригинальная' struct', а код правильный как он есть. 'c.values.values ​​[0]' будет ошибкой компилятора. –

+0

whoa, не удалось заметить typedef. –

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 то же самое на вашей платформе и операционной системы .. принимая во внимание 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;  
} 
+0

Ваша альтернатива 2 заставила меня найти оператора трансляции, поэтому 'color' можно было бы написать как' struct color {float r, g, b; оператор vec3f &() {return * ((vec3f *) this); }; '. – wjd

1

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

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

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

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

+0

В то время как аккуратный трюк, я не вижу, как это помогает, когда 'color' должен быть' vec3f'. –

+0

@MooingDuck Если мы собираемся сделать что-то странное, как обрабатывать цвета в виде векторов, я почти не вижу, как важно, в каком направлении происходит наследование, или даже что есть наследование ... так что вы делаете «цвет» с перегруженными членами 'operator []' и 'r/g/b', а затем typedef' vec3f'. –

Смежные вопросы