我在为模板类定义一些运算符重载时遇到了一些问题。让我们以这个假设的类为例。
template <class T>
class MyClass {
// ...
};
operator+=
// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);
// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
// ...
return *this;
}
导致这个编译器错误。
no match for 'operator+=' in 'classObj2 += classObj1'
operator<<
// In MyClass.h
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
// In MyClass.cpp
template <class T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
// ...
return out;
}
导致这个编译器警告。
friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function
我在这里做错了什么?
// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);
// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
// ...
return *this;
}
这对于模板来说是无效的。操作符的完整源代码必须在所有使用它的翻译单元中。这通常意味着代码在头中是内联的。
编辑:从技术上讲,根据标准,是可以导出模板的,然而很少有编译器支持它。另外,如果在MyClass.cpp中明确实例化了所有类型都是T-的模板,你也可以做上述操作,但实际上,这通常违背了模板的意义。
更多编辑:我读了你的代码,它需要一些工作,例如重载operator[]。另外,通常情况下,我会将维度作为模板参数的一部分,允许在编译时捕捉到+或+=的失败,并允许类型被有意义地堆栈分配。你的异常类也需要派生自std::exception。然而,这些都不涉及编译时的错误,只是代码不怎么样。
你需要说下面的话(因为你结交了一个完整的 模板 而不是仅仅是它的一个特殊化,在这种情况下,您只需要添加一个 <>
之后 operator<<
):
template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
其实,没有必要宣布它为朋友 除非它访问私人或受保护的成员。因为你只是得到一个 警告,看来你的友谊宣言并不是一个好主意。如果你只是想宣布一个 单专 的朋友,你可以像下图所示那样,在你的类之前声明一个前向的模板,这样 operator<<
被认作是一个模板。
// before class definition ...
template <class T>
class MyClass;
// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);
以上和这种方式都声明它的特殊化为朋友,但第一种方式声明了 都 专门化为朋友,而第二种只声明专门化为朋友。operator<<
作为朋友 T
等于 T
的类授予友谊。
而在另一种情况下,你的声明看起来是可以的,但请注意,你不能 +=
a MyClass<T>
到 MyClass<U>
当 T
和 U
是不同的类型(除非你在这些类型之间有一个隐式转换)。你可以让你的 +=
模板
// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);
// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
// ...
return *this;
}
这对我有帮助 有着完全相同的问题。
解决办法。
向前声明 friend
函数的定义之前的 class
本身。例如:在你的类中声明你的友情函数。
template<typename T> class MyClass; // pre-declare the template class itself
template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
在你的类中声明你的朋友函数,并在函数名后面加上"<>"。
friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
这种方式可行。
class A
{
struct Wrap
{
A& a;
Wrap(A& aa) aa(a) {}
operator int() { return a.value; }
operator std::string() { stringstream ss; ss << a.value; return ss.str(); }
}
Wrap operator*() { return Wrap(*this); }
};