假设我想要打印一个类成员,我试图为成员重载operator<<
:
#include <iostream>
#include <map>
template <typename K, typename V>
class MyClass {
public:
typedef std::map<K, V> MyMapType;
MyMapType mymap;
friend std::ostream& operator<<(
std::ostream& _os, const typename MyClass<K, V>::MyMapType& _map) {
for (auto p : _map) _os << p.first << std::endl;
}
};
int main(int argc, char const* argv[]) {
MyClass<std::string, int> c;
c.mymap["a"] = 1;
c.mymap["b"] = 2;
std::cout << c.mymap << std::endl;
return 0;
}
但编译器似乎忽略了定义:
error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'MyMapType' (aka
'map<std::__1::basic_string<char>, int>'))
std::cout << c.mymap << std::endl;
~~~~~~~~~ ^ ~~~~~~~
那我该怎么正确地重载这个呢?我是否必须在类中创建一个类,或者我是否需要提供std :: map的派生?
答案 0 :(得分:2)
它只需要在课外:
template <typename K,typename V>
std::ostream& operator<<(
std::ostream& _os,
const std::map<K,V> _map
) {
for (auto& p : _map) _os << p.first << "\n";
return _os;
}
这是有效的,因为MyMapType
只是std::map
的别名,因此如果要打印MyMapType
的实例,则只需打印常规std::map
。< / p>
您的原始示例不起作用,因为您没有MyClass类型的参数,因此无法在MyClass中找到该函数。朋友函数只能在类外部声明,或者如果它们具有类的类型参数,则只能在类外找到。
答案 1 :(得分:0)
对不起,@ Vaugh Cato,但问题与friend
声明无关。无论如何都没有必要,因此应该避免。
@chad luo:“一流的朋友功能”应该是什么?这没有任何意义。
此处编译器错误消息具有误导性。找不到该功能,因为它不存在。您已在左侧定义了一个运算符MyClass<...>
,右侧是流和地图。在找不到合理的声明之前,编译器应该抱怨无意义的声明。
如果您将运算符定义为成员函数,则运算符的左参数始终为this
:
class A { /*...*/ };
class B { /*...*/ };
class C {
public:
A operator << (const B& rhs);
/*...*/
};
C c;
B b;
A a = c << b;
对于流操作,您需要在左侧使用流对象,在右侧使用this
。理论上,您可以在流类中指定运算符,但不能在用户类中指定。由于流类来自标准库,因此不是一个选项。所以你只需使用外部运算符定义。您可以在里面调用成员函数,以避免声明流操作符friend
:
class A {
public:
writeToStream(std::ostream& stream) const;
/*...*/
};
std::ostream& operator << (std::ostream& stream, const A& a) {
a.writeToStream(stream);
return stream;
};
这些函数都不必声明为friend
。避免像瘟疫一样friend
。只有极少数非常罕见的情况才需要它。不要使用它,只要你不是100%确定,你的情况就是其中之一。
所以这里是完整的示例更正(未经测试,因此要注意错误):
#include <iostream>
#include <map>
template <typename K, typename V>
class MyClass {
public:
typedef std::map<K, V> MyMapType;
MyMapType mymap;
};
template <typename K, typename V>
std::ostream& operator<<(std::ostream& stream,
const typename MyClass<K, V>::MyMapType& map) {
for (auto p : map)
stream << p.first << std::endl;
return stream;
}
int main(int argc, char const* argv[]) {
MyClass<std::string, int> c;
c.mymap["a"] = 1;
c.mymap["b"] = 2;
std::cout << c.mymap << std::endl;
return 0;
}
在您的示例中,您甚至无法访问MyClass<...>
中的任何内容。甚至没有远程理由声明它friend
。
BTW。:std::endl
也会刷新流。考虑在运营商中使用"\n"
。