在另一个模板类 [duplicate] 中的类中定义友元运算符==时出错

Error when defining friend operator== in a class within another template class [duplicate]

提问人:TheMemeMachine 提问时间:9/14/2023 更新时间:9/14/2023 访问量:56

问:

我有一个模板类和另一个类。我必须为该内部类定义 operator==,但定义和定义是分开的。下面是一个最小的可重现示例:

#include <iostream>

namespace myNamespace {
    template <typename T>
    class MyClass {
        public:
            class MyInnerClass {
                public:
                    MyInnerClass() : v{0} {};

                    // declaration
                    template <typename U>
                    friend bool operator==(const typename MyClass<U>::MyInnerClass& lhs, const typename MyClass<U>::MyInnerClass& rhs);

                private:
                    int v;
            };

        private:
            // ...
    };
}

namespace myNamespace {
    // definition
    template <typename U>
    bool operator==(const typename MyClass<U>::MyInnerClass& lhs, const typename MyClass<U>::MyInnerClass& rhs) {
        return lhs.v == rhs.v;
    }
}


int main() {
    using namespace myNamespace;

    MyClass<int>::MyInnerClass inner1;
    MyClass<int>::MyInnerClass inner2;
    
    // fails here
    std::cout << (inner1 == inner2) << std::endl;

    return 0;
}

我得到的错误是:

tmp.cpp:39:26: error: no match for ‘operator==’ (operand types are ‘myNamespace::MyClass<int>::MyInnerClass’ and ‘myNamespace::MyClass<int>::MyInnerClass’)
   39 |     std::cout << (inner1 == inner2) << std::endl;
      |                   ~~~~~~ ^~ ~~~~~~
      |                   |         |
      |                   |         MyInnerClass<[...]>
      |                   MyInnerClass<[...]>
tmp.cpp:27:10: note: candidate: ‘template<class U> bool myNamespace::operator==(const typename myNamespace::MyClass<U>::MyInnerClass&, const typename myNamespace::MyClass<U>::MyInnerClass&)’
   27 |     bool operator==(const typename MyClass<U>::MyInnerClass& lhs, const typename MyClass<U>::MyInnerClass& rhs) {
      |          ^~~~~~~~
tmp.cpp:27:10: note:   template argument deduction/substitution failed:
tmp.cpp:39:29: note:   couldn’t deduce template parameter ‘U’
   39 |     std::cout << (inner1 == inner2) << std::endl;
      |                             ^~~~~~

我如何使模板运算符==专业化,这样就不会失败

C++ C++11 模板

评论


答:

0赞 Eugene 9/14/2023 #1

不要为 - use(外部类模板参数)引入新的模板参数。此外,您必须将定义与声明结合起来(因为以这种方式声明的只有通过 ADL 才能看到):friendTfriend

#include <iostream>

namespace myNamespace {
template <typename T>
class MyClass {
public:
   class MyInnerClass {
   public:
      MyInnerClass() : v{ 0 } {};

      friend bool operator==(const typename MyClass<T>::MyInnerClass& lhs, const typename MyClass<T>::MyInnerClass& rhs)
      {
         return lhs.v == rhs.v;
      }

   private:
      int v;
   };

private:
    // ...
};
}

评论

0赞 TheMemeMachine 9/14/2023
我在这里很困惑。为什么在这种情况下我不能将声明和定义分开,但是如果我在类中没有类,我可以这样做?下面是一个编译良好的示例:godbolt.org/z/8h77eGMY4
1赞 Jan Schultke 9/14/2023 #2

窗体的运算符重载

template <typename U>
bool operator==(const typename MyClass<U>::MyInnerClass& lhs,
                const typename MyClass<U>::MyInnerClass& rhs);

...无论在哪里定义它,实际上都是无用的,因为这是一个非推导的上下文。从这样的函数参数中推导出是不可能的,所以调用它的唯一方法是通过MyClass<U>::MyInnerClassU

myNamespace::operator==<MyType>(a, b);

相反,您可以将运算符重载定义为声明当前所在的隐藏友元:friend

// note: MyClass<T>:: can be omitted here
friend bool operator==(const MyInnerClass& lhs, const MyInnerClass& rhs) {
    return lhs.v == rhs.v;
}

查看 Compiler Explorer 中的实时示例

通常,此解决方案是可取的,因为它使运算符重载为非模板。

请参阅类似的问题:模板化类友元运算符成员函数