C++ 运算符歧义

发布于 2024-07-10 19:55:24 字数 1084 浏览 14 评论 0原文

请原谅我,因为我对 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 上定义时,为什么它会首先尝试将我的 Vector4 转换为 GLfloat*? 有没有一种不涉及类型转换的简单方法来解决这个问题? 我只是犯了一个愚蠢的错误吗? 感谢您提前提供的任何帮助。

Forgive me, for I am fairly new to C++, but I am having some trouble regarding operator ambiguity. I think it is compiler-specific, for the code compiled on my desktop. However, it fails to compile on my laptop. I think I know what's going wrong, but I don't see an elegant way around it. Please let me know if I am making an obvious mistake. Anyhow, here's what I'm trying to do:

I have made my own vector class called Vector4 which looks something like this:

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

Then I have these operators, which are causing the problem:

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

I have the conversion operator so that I can pass an instance of my Vector4 class to glVertex3fv, and I have subscripting for obvious reasons. However, calls that involve subscripting the Vector4 become ambiguous to the compiler:

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

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

Here are the candidates:

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

Why would it try to convert my Vector4 to a GLfloat* first when the subscript operator is already defined on Vector4? Is there a simple way around this that doesn't involve typecasting? Am I just making a silly mistake? Thanks for any help in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

离笑几人歌 2024-07-17 19:55:24

《C++ 模板 - 完整指南》一书中对此进行了解释。 这是因为你的operator[]接受size_t,但是你传递了一个不同的类型,它首先必须经历到size_t的隐式转换。 另一方面,也可以选择转换运算符,然后返回的指针可以是下标。 所以存在歧义。 解决方案是删除转换运算符。 通常应该避免它们,因为它们只会带来问题,如您所见。

提供一个 beginend 成员函数,分别返回 vectorvector + 4。 然后,如果您想传递给本机 openGL 函数,则可以使用 v.begin()

评论里有点混乱。 我想我现在会更新这个答案以反映最新的概念。

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

This is explained in the book "C++ Templates - The Complete Guide". It's because your operator[] takes size_t, but you pass a different type which first has to undergo an implicit conversion to size_t. On the other side, the conversion operator can be chosen too, and then the returned pointer can be subscript. So there is the ambiguity. Solution is to drop the conversion operator. They should generally be avoided as they just introduce problems, as you see.

Provide a begin and end member function that returns vector and vector + 4 respectively. Then you can use v.begin() if you want to pass to native openGL functions.

There is a bit confusion in the comments. I think i will update this answer now to reflect the most recent concept of this.

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];
}
终遇你 2024-07-17 19:55:24

摆脱歧义太难了。 它可以轻松地将其解释为直接 [] 访问,或转换为 float* 后跟数组索引。

我的建议是放弃运算符 GLfloat*。 让隐式强制转换以这种方式浮动只是自找麻烦。 如果必须直接访问浮点数,请为 Vector4 创建一个 get() (或您选择的其他名称)方法,该方法返回指向下面的原始浮点数的指针。

其他随机建议:您应该使用“IlmBase”包中的优秀矢量类,而不是重新发明自己的矢量类,该包是 OpenEXR

It's too hard to get rid of the ambiguity. It could easily interpret it as the direct [] access, or cast-to-float* followed by array indexing.

My advice is to drop the operator GLfloat*. It's just asking for trouble to have implicit casts to float this way. If you must access the floats directly, make a get() (or some other name of your choice) method to Vector4 that returns a pointer to the raw floats underneath.

Other random advice: rather than reinvent your own vector classes, you should use the excellent ones in the "IlmBase" package that is part of OpenEXR

仙女 2024-07-17 19:55:24

为什么要将“const size_t”传递给operator[]?

Why are you passing a "const size_t" to operator[] ?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文