C ++ псевдонимы переменных-членов? - PullRequest
12 голосов
/ 30 января 2009

Я почти уверен, что это возможно, потому что я уверен, что видел, как это было сделано. Я думаю, что это здорово, но я с радостью приму ответы в духе «это ужасная идея, потому что ____».

Скажем, у нас есть базовая структура.

struct vertex
{
    float x, y, z;
};

Теперь я хочу реализовать псевдонимы для этих переменных.

vertex pos;
vertex col;
vertex arr;

pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;

В идеале третий синтаксис был бы неотличим от массива. То есть, если бы я отправил arr в качестве ссылочного параметра в функцию, ожидающую массив чисел с плавающей запятой, в которые он будет хранить данные (например, многие функции OpenGL glGet), он бы работал нормально.

Что вы думаете? Возможный? Возможно, но глупо?

Ответы [ 12 ]

0 голосов
/ 30 января 2009

Вы можете попробовать добавить ссылки на переменные, например:

struct test {
        float x, y, z;
        float &r, &g, &b;

        test() : r(x), g(y), b(z) {}
    };

Но ваша структура становится больше (от 12 байтов до 40 байтов).

Чтобы использовать [] для него, используйте перегрузку оператора [], как упоминалось ранее.

0 голосов
/ 30 января 2009

У меня есть шаблон и два векторных класса ниже, один сумасшедший, один вменяемый. Шаблон реализует простой фиксированный во время компиляции массив значений. Он предназначен для создания подклассов и использует переменную защищенного массива, чтобы вам не приходилось прыгать через обручи для доступа к массиву. (Некоторым людям может не понравиться такой дизайн. Я говорю, если ваши подклассы вызывают ваши перегруженные операторы, связывание может быть хорошей идеей.)

Сумасшедший класс позволяет вам иметь переменные-члены с именами x, y, z, и он действует как массив для вызовов glGetFloatV. У здравомыслящего только есть функции доступа x (), y (), z () и все еще работает с glGetFloatV. Вы можете использовать любой класс в качестве основы для других векторных объектов, которые вы можете передать в библиотеку OpenGL. Хотя приведенные ниже классы относятся только к точкам, очевидно, вы можете просто выполнить поиск / замену, чтобы превратить их в цветовые классы rgb.

Сумасшедший класс сумасшедший, потому что стоимость синтаксического сахара vec.x вместо vec.x () равна 3 ссылочным переменным. Это может занять много места в большом приложении. Используйте более простую и разумную версию.

template <typename T, int N>
class FixedVector {
protected:
    T arr[N];
public:
    FixedVector();

    FixedVector(const T* a) {
        for (int i = 0; i < N; ++i) {
            arr[i] = a[i];
        }
    }

    FixedVector(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
    }

    FixedVector& operator=(const T& other) {
        for (int i = 0; i < N; ++i) {
            arr[i] = other.arr[i];
        }
        return *this;
    }

    T* operator&() { return arr; }
    const T* operator&() const { return arr; }

    T& operator[](int ofs) { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
    const T& operator[](int ofs) const { 
        assert(ofs >= 0 && ofs < N);
        return arr[ofs];
    }
};

class CrazyPoint :  public FixedVector<float, 3> {
public:
    float &x, &y, &z;

    CrazyPoint()
      : x(arr[0]), y(arr[1]), z(arr[2])
    { arr[0] = arr[1] = arr[2] = 0.0; }

    CrazyPoint(const float* a)
      : x(arr[0]), y(arr[1]), z(arr[2])
    {
        arr[0] = a[0];
        arr[1] = a[1];
        arr[2] = a[2];
    }

    CrazyPoint(float a, float b, float c) 
      : x(a), y(b), z(c)
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

class SanePoint : public FixedVector<float, 3> {
public:
    float& x() { return arr[0]; }
    float& y() { return arr[1]; }
    float& z() { return arr[2]; }

    SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
    SanePoint(float a, float b, float c) 
    {
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
    }
};

// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);
...