C ++ Operator Ambiguity - PullRequest
       25

C ++ Operator Ambiguity

3 голосов
/ 21 декабря 2008

Простите, я довольно новичок в C ++, но у меня возникли некоторые проблемы с неоднозначностью операторов. Я думаю, что это зависит от компилятора, для кода, скомпилированного на моем рабочем столе. Тем не менее, он не может скомпилировать на моем ноутбуке. Я думаю, что знаю, что происходит не так, но я не вижу элегантного способа обойти это. Пожалуйста, дайте мне знать, если я делаю очевидную ошибку. Во всяком случае, вот что я пытаюсь сделать:

Я создал свой собственный векторный класс под названием Vector4, который выглядит примерно так:

class Vector4
{
 private:
   GLfloat vector[4];
 ...
}

Тогда у меня есть эти операторы, которые вызывают проблему:

operator GLfloat* () { return vector; }

operator const GLfloat* () const { return vector; }

GLfloat& operator [] (const size_t i) { return vector[i]; }

const GLfloat& operator [] (const size_t i) const { return vector[i]; }

У меня есть оператор преобразования, так что я могу передать экземпляр моего класса Vector4 в glVertex3fv, и у меня есть подписка по очевидным причинам. Однако вызовы, которые включают в себя подписку Vector4, становятся для компилятора неоднозначными:

enum {x, y, z, w}
Vector4 v(1.0, 2.0, 3.0, 4.0);

glTranslatef(v[x], v[y], v[z]);

Вот кандидаты:

candidate 1: const GLfloat& Vector4:: operator[](size_t) const
candidate 2: operator[](const GLfloat*, int) <built-in>

Зачем пытаться сначала преобразовать мой Vector4 в GLfloat *, когда оператор индекса уже определен в Vector4? Есть ли простой способ обойти это, который не включает в себя приведение типов? Я просто делаю глупую ошибку? Спасибо за любую помощь заранее.

Ответы [ 3 ]

6 голосов
/ 21 декабря 2008

Это объясняется в книге «Шаблоны C ++ - Полное руководство». Это потому, что ваш оператор [] принимает size_t, но вы передаете другой тип, который сначала должен пройти неявное преобразование в size_t. С другой стороны, оператор преобразования также может быть выбран, и тогда возвращаемый указатель может быть нижним индексом. Так что тут есть двусмысленность. Решение заключается в отбрасывании оператора преобразования. Как правило, их следует избегать, поскольку они просто создают проблемы, как вы видите.

Предоставляет функции-члены begin и end, которые возвращают vector и vector + 4 соответственно. Тогда вы можете использовать v.begin(), если хотите перейти к собственным функциям openGL.

В комментариях есть небольшая путаница. Я думаю, что я обновлю этот ответ сейчас, чтобы отразить самую последнюю концепцию этого.

struct Vector4 {
    // some of container requirements
    typedef GLfloat value_type;
    typedef GLfloat& reference;
    typedef GLfloat const& const_reference;

    typedef GLfloat * iterator;
    typedef GLfloat const * const_iterator;

    typedef std::ptrdiff_t difference_type;
    typedef std::size_t size_type;

    static const size_type static_size = 4;

    // returns iterators to the begin and end
    iterator begin() { return vector; }
    iterator end() { return vector + size(); }

    const_iterator begin() const { return vector; }
    const_iterator end() const { return vector + size(); }

    size_type size() const { return static_size; }
    size_type max_size() const { return static_size; }

    void swap(Vector4 & that) {
        std::swap(*this, that);
    }

    // some of sequences
    reference operator[](size_type t) { return vector[t]; }
    const_reference operator[](size_type t) const { return vector[t]; }

    // specific for us. returns a pointer to the begin of our buffer.
    // compatible with std::vector, std::array and std::string of c++1x
    value_type * data() { return vector; }
    value_type const* data() const { return vector; }

    // comparison stuff for containers
    friend bool operator==(Vector4 const&a, Vector4 const&b) {
        return std::equal(a.begin(), a.end(), b.begin());
    }
    friend bool operator!=(Vector4 const&a, Vector4 const&b) { return !(a == b); }
    friend bool operator<(Vector4 const&a, Vector4 const&b) {
        return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
    }
    friend bool operator> (Vector4 const&a, Vector4 const&b) { return b < a;    }
    friend bool operator<=(Vector4 const&a, Vector4 const&b) { return !(b < a); }
    friend bool operator>=(Vector4 const&a, Vector4 const&b) { return !(a < b); }

private:
    GLfloat vector[4];
}
1 голос
/ 21 декабря 2008

Слишком сложно избавиться от двусмысленности. Он может легко интерпретировать его как прямой доступ [] или приведение к плавающей точке * с последующей индексацией массива.

Мой совет - бросить оператор GLfloat *. Это просто напрашивается на неприятности иметь неявные приведения, чтобы плавать таким образом. Если вам нужен прямой доступ к числам с плавающей точкой, создайте метод get () (или другое имя по вашему выбору) для Vector4, который возвращает указатель на необработанные числа с плавающей точкой под ним.

Другой случайный совет: вместо того, чтобы заново изобретать свои собственные векторные классы, вы должны использовать отличные в пакете "IlmBase", который является частью OpenEXR

0 голосов
/ 21 декабря 2008

Почему вы передаете "const size_t" оператору []?

...