Неоднозначность оператора C ++
-
23-08-2019 - |
Вопрос
Простите меня, поскольку я довольно новичок в 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?Есть ли простой способ обойти это, который не включает приведение типов?Я просто совершаю глупую ошибку?Заранее спасибо за любую помощь.
Решение
Это объясняется в книге "Шаблоны C ++ - полное руководство".Это потому, что ваш operator[] принимает 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];
}
Другие советы
Слишком трудно избавиться от двусмысленности.Он мог бы легко интерпретировать это как прямой доступ [] или преобразование с плавающей точкой *, за которым следует индексация массива.
Мой совет - отказаться от оператора GLfloat*.Это просто напрашивается на неприятности, когда неявные приведения используются таким образом.Если вам необходимо получить прямой доступ к элементам с плавающей точкой, создайте метод get() (или какое-либо другое имя по вашему выбору) для Vector4, который возвращает указатель на необработанные элементы с плавающей точкой внизу.
Другой случайный совет:вместо того чтобы изобретать свои собственные векторные классы, вам следует использовать отличные из пакета "IlmBase", который является частью OpenEXR ( Открытый EXR )
Почему вы передаете "const size_t" оператору[]?