提问人:Leon 提问时间:9/30/2019 最后编辑:Leon 更新时间:10/13/2019 访问量:518
为什么我不能用 ostream 和 map( 或 unordered_map) 重载运算符<<?
Why can not I overload operator<< with ostream and map( or unordered_map)?
问:
我有一个派生自 std::ostringstream 的类,并编码了一个流输出喜欢的运算符<< friend-func,这样我就有机会在真正的流输出发生之前预处理一些东西。 但是,如果 << 的第二个操作数是 std::map(或 unordered_map) 的对象,我的代码就不能用 GCC 进行编译,而可以接受许多其他类型的第二个操作数。我尝试了 int、string、c-string、vector 等......他们都没问题,但地图和unordered_map。
下面是一个最小的可重现示例:
#include <iomanip>
#include <iostream>
#include <map>
#include <ostream>
#include <sstream>
#include <string_view>
#include <vector>
#include <unordered_map>
using namespace std;
enum class LogLevel { Debug, Infor, Notif, Warnn, Error, Fatal };
constexpr string_view LevelNames[] { "Debug", "Infor", "Notif", "Warnn", "Error", "Fatal" };
LogLevel sysLogLevel { LogLevel::Debug };
class Logger : public ostringstream {
public:
Logger( LogLevel lv ) : logLevel( lv ) {};
~Logger() override {
cout << LevelNames[static_cast<int>( logLevel )] << ':' << str() << '\n';
};
LogLevel logLevel;
};
template <typename T>
inline Logger& operator<<( Logger& lg, const T& body ) {
if ( lg.logLevel >= sysLogLevel )
static_cast<std::ostream&>( lg ) << body;
return lg;
};
using StrStrMap = map<string, string>;
inline ostream& operator<<( ostream& os, const StrStrMap& ssm ) {
os << '{';
for ( const auto& [k,v] : ssm )
os << k << ':' << v << ',';
os << '}';
return os;
};
int main() {
StrStrMap ssm1 { { "Flower", "Red" }, { "Grass", "Green" } };
cout << ssm1 << endl; // OK!
{ Logger log { LogLevel::Fatal }; log << ssum1; } // OK!
Logger(LogLevel::Infor) << ssm1; // Compiling Error!
return EXIT_SUCCESS;
};
GCC 的错误消息是:
/usr/include/c++/8/ostream:656:11:错误:不匹配(操作数类型为 和
operator<<
std::basic_ostream<char>
const std::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >
)
正如 @n.m. 所指出的,它看起来像“不能将左值引用绑定到临时对象”。
但是,当第二个操作数是其他类型的操作数(例如 int、string、c-string、vector 等)时,为什么可以这样做呢?
这是我对其他类型的尝试:
template<typename T>
class MyIntTemplate {
public:
MyIntTemplate( T p ) : payLoad(p) {};
T payLoad;
};
using MyInt = MyIntTemplate<int>;
inline ostream& operator<<( ostream& os, const MyInt& mi ) {
os << mi.payLoad;
return os;
};
using StrVec = vector<string>;
inline ostream& operator<<( ostream& os, const StrVec& sv ) {
os << '{';
for ( const auto& v : sv )
os << v << ',';
os << '}';
return os;
};
int main() {
Logger(LogLevel::Infor) << MyInt(123); // OK!
Logger(LogLevel::Warnn) << 456; // OK!
Logger(LogLevel::Debug) << "a Debugging Log"; // OK!
Logger(LogLevel::Infor) << string( "a Informing Log" ); // OK!
StrVec sv1 { "Flower", "Grass" };
Logger(LogLevel::Fatal) << sv1; // OK!
return EXIT_SUCCESS;
};
因为另一个原因,我真的需要伐木器是temorary。 有人能给我一个解决方案吗? 任何提示都会被理解!
答:
Logger(LogLevel::Warnn)
是暂时的。非常量引用不能绑定到临时引用。
inline ostream& operator<<( ostream& os,
// -------- <------ nope
评论
执行 IOStreams 所做的操作,并为 rvalues 创建一个包罗万象的重载:
template<class T>
Logger& operator<<(Logger&& lg, T const& x) {
return lg << x;
}
评论
inline Logger& operator<<( Logger& os, const StrStrMap& ssm ) {...}