“多个运算符”!=“与这些操作数匹配”错误未停止编译?

"More than one operator "!=" matches these operands" error not stopping compilation?

提问人:Henry Nissen 提问时间:11/2/2023 更新时间:11/2/2023 访问量:66

问:

因此,我有一个模板类,它本质上只是另一个变量的包装器,这样我就可以为该变量设置目标值以及达到该值需要多少帧。每一帧,我都会调用一个进程函数,将其值向目标值移动。TargetVarTargetVar

这是课程:

class BaseTargetVar {
public:
    BaseTargetVar() {
        TargetVarManager::get_instance()->register_target_var(this); //TargetVarManager just iterates 
        //through all registered TargetVars and calls their process funcs
    }
    virtual ~BaseTargetVar() {
        TargetVarManager::get_instance()->unregister_target_var(this);
    }

    virtual void process() {}
};

template <class T> class TargetVar : public BaseTargetVar {
public:
    TargetVar() = default;


    TargetVar(T& other) {
        if (val != other) {
            val = other;
            frames = 0;
        }
    }
    
    TargetVar(const T& other) {
        if (val != other) {
            val = other;
            frames = 0;
        }
    }

    void process() override {
        if (frames) {
            val += target_change_per_frame;
            frames--;
            if (!frames) {
                val = target_val;
            }
        }
    }
    
    void set_target_val(T target_val, unsigned int frames) {
        if (target_val == this->target_val) return;
        this->target_val = target_val;
        target_change_per_frame = target_val - val;
        target_change_per_frame /= frames;
        this->frames = frames;
    }

    void set_val(const T& val) {
        this->val = val;
    }

    T get_val() const {
        return val;
    }

    T* get_val_addr() const {
        return &val;
    }

    T get_target_change_per_frame() const {
        return target_change_per_frame;
    }

    unsigned int get_frames() const {
        return frames;
    }
private:
    T val{};
    T target_val{};
    T target_change_per_frame{};
    unsigned int frames = 0;
};

在我的项目中,此类的主要用途之一是使用 a 来处理纹理的位置。因此,通常将 a 与 a 进行比较(例如,将纹理的位置与屏幕上的位置进行比较,即 to ),但将一个纹理与另一个纹理进行比较也很常见(例如,将纹理的位置与另一个纹理的位置进行比较,即 更改为 )。为了更方便,我在类中添加了以下运算符重载:TargetVar<glm::vec3>TargetVar<T>TTargetVar<glm::vec3>glm::vec3TargetVar<T>TargetVar<T>TargetVar<glm::vec3>TargetVar<glm::vec3>TargetVar

    template <typename U>
    TargetVar<T>& operator=(const U& rhs) {
        val = (T)rhs;
        frames = 0;
        return *this;
    }

    template <typename U>
    bool operator==(const U& rhs) {
        return val == rhs;
    }

    template <typename U>
    bool operator!=(const U& rhs) {
        return val != rhs;
    }

    template <typename U>
    TargetVar<T>& operator=(const TargetVar<U>& rhs) {
        if (this != &rhs) {
            val = rhs.get_val();
            frames = 0;
        }
        return *this;
    }

    template <typename U>
    bool operator==(const TargetVar<U>& rhs) {
        return val == rhs.get_val();
    }

    template <typename U>
    bool operator!=(const TargetVar<U>& rhs) {
        return val != rhs.get_val();
    }

这个系统已经工作了几个星期,没有任何问题,但我注意到某些比较会导致 VS 出现错误。例如:

    TargetVar<glm::vec3> tv1 = glm::vec3(0.0);
    TargetVar<glm::vec3> tv2 = glm::vec3(0.0);
    if (tv1 != tv2) {
        /*
            Error E0350 - more than one operator "!=" matches these operands:
            function template "bool TargetVar<T>::operator==(const U &rhs) [with T=glm::vec3]", with reversed arguments
            function template "bool TargetVar<T>::operator==(const TargetVar<U> &rhs) [with T=glm::vec3]", with reversed arguments
            function template "bool TargetVar<T>::operator!=(const U &rhs) [with T=glm::vec3]"
            function template "bool TargetVar<T>::operator!=(const TargetVar<U> &rhs) [with T=glm::vec3]"
            operand types are: TargetVar<glm::vec3> != TargetVar<glm::vec3>
        */
    }
    if (tv1 == tv2) {
        /*
            Error E0350 - more than one operator "==" matches these operands:
            function template "bool TargetVar<T>::operator==(const U &rhs) [with T=glm::vec3]", with reversed arguments
            function template "bool TargetVar<T>::operator==(const TargetVar<U> &rhs) [with T=glm::vec3]", with reversed arguments
            function template "bool TargetVar<T>::operator==(const U &rhs) [with T=glm::vec3]"
            function template "bool TargetVar<T>::operator==(const TargetVar<U> &rhs) [with T=glm::vec3]"
            operand types are: TargetVar<glm::vec3> == TargetVar<glm::vec3>

        */
    }
    if (tv1 != tv2.get_val()) {
        //No errors
    }
    if (tv1 == tv2.get_val()) {
        //No errors
    }
    if (tv1.get_val() != tv2.get_val()) {
        //No errors
    }
    if (tv1.get_val() == tv2.get_val()) {
        //No errors
    }

这些错误实际上并没有阻止程序编译,但我想知道为什么 VS 认为 tv1 到 tv2 的比较有问题,而不是 tv1 到 tv2.get_val() 的比较有问题。

此外,出于好奇,我删除了 != 运算符重载,看看“带有反向参数”位是否会消失。它没有对现有错误进行任何更改,但它确实引入了以下错误,这些错误确实导致程序无法编译:

if (tv1 != tv2) {
    /*
        Error C2666 - 'TargetVar<glm::vec3>::operator ==': overloaded functions have similar conversions
    */
}
if (tv1 == tv2) {
    /*
        Error C2666 - 'TargetVar<glm::vec3>::operator ==': overloaded functions have similar conversions
    */
}

归根结底,该程序按原样运行良好,但我想知道为什么 VS 只在特定情况下有问题,以及除了手动将 .get_val() 放入我的所有操作之外,我是否还能做些什么。

C++ 模板 运算符重载

评论

0赞 tbxfreeware 11/2/2023
这可能与您的问题无关,但是当比较运算符作为成员函数实现时,应将其标记为 。例如:。否则,您将难以使用它们来比较非常量对象。consttemplate <typename U> bool operator==(const U& rhs) const { ... }

答:

3赞 Ben Voigt 11/2/2023 #1

所以。。。。 运行生成时,序列错误来自实际编译器。 错误来自编辑器。编辑器对 C++ 代码的解释有时有点不稳定,因为它努力找出无效的代码,因为它正在编辑过程中。不再与类本身的声明匹配的类成员主体,诸如此类。CxxxxExxxx

当编辑器出错时,它会影响“GoTo Definition”等操作,但不会阻止您构建。

编辑器经常出错,以至于我通常会从“错误列表”顶部的下拉列表中关闭编辑器的错误/警告消息。

enter image description here

实际上,我甚至几乎不使用“错误列表”窗口,而是更喜欢“输出”窗口的“构建”选项卡,在那里可以看到完整的错误消息,而无需强制进入整齐的 n 列表。