如何在自定义Logger类的operator<<中支持std::hex格式化?
问题
我已经在自定义Logger类中实现了operator<<重载,代码如下:
#pragma once #include <map> #include <vector> #include <string> class Logger { public: enum Severity { INFORMATION = 0, WARNING = 1, ERROR = 2 }; Logger( std::ostream &os, Logger::Severity severity ) : outputStream( os ), loggerSeverity( severity ) {} const std::vector<std::string>& getLogLines() const { return logLines; } friend Logger& operator<<( Logger &logger, Logger::Severity severity ) { logger.currentSeverity = severity; logger.outputStream << logger.severityMap.find( severity )->second << ": "; return logger; } friend Logger& operator<<( Logger &logger, const char *logLine ) { if( logger.currentSeverity >= logger.loggerSeverity ) { logger.logLines.push_back( logLine ); logger.outputStream << logLine; } return logger; } private: std::ostream &outputStream; Logger::Severity loggerSeverity; std::vector<std::string> logLines; Logger::Severity currentSeverity; const std::map<Logger::Severity, std::string> severityMap = { { Logger::Severity::INFORMATION, "<INF>" }, { Logger::Severity::WARNING, "<WARN>" }, { Logger::Severity::ERROR, "<ERR>" } }; };
现在我希望该Logger能支持std::hex格式化,期望调用方式如下:
logger << Logger::Severity::ERROR << "CRC mismatch ( expected 0x" << std::hex << record->metaData.crc << " but got 0x" << std::hex << crc32 << std::dec << " )" << "\n";
但编译时出现如下错误:
error: no match for ‘operator<<’ (operand types are ‘Logger’ and ‘std::ios_base&(std::ios_base&)’) 79 | logger << Logger::Severity::ERROR << "CRC mismatch ( expected 0x" << std::hex << record->metaData.crc << " but got 0x" << std::hex << crc32 << std::dec << " )" << "\n"; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~ ~~~~~~~~ | | | | Logger std::ios_base&(std::ios_base&)
请问如何解决此问题,使Logger支持std::hex格式化?
解决方案
处理操纵符函数的重载
编译错误的核心原因是std::hex、std::dec这类属于ios操纵符函数,它们的类型是std::ios_base&(*)(std::ios_base&),而你的Logger类没有提供对应的operator<<重载来处理这类函数。添加以下友元重载即可让Logger传递这些操纵符到底层的输出流:
#include <iostream> // 必须包含此头文件以引用std::ios_base friend Logger& operator<<(Logger& logger, std::ios_base& (*manip)(std::ios_base&)) { if (logger.currentSeverity >= logger.loggerSeverity) { manip(logger.outputStream); } return logger; }这个重载会把操纵符直接应用到
Logger内部的outputStream上,后续的数值输出就会遵循指定的格式(比如十六进制)。添加数值类型的输出重载
你当前的Logger只实现了const char*类型的输出,而record->metaData.crc和crc32是整数类型,所以还需要补充对应的数值类型重载,比如:#include <sstream> // 要包含这个头文件来使用std::ostringstream // 处理无符号整数 friend Logger& operator<<(Logger& logger, unsigned int value) { if (logger.currentSeverity >= logger.loggerSeverity) { // 如果需要在logLines中保存格式化后的内容,先转成字符串再存入 std::ostringstream oss; oss << logger.outputStream.flags() << value; logger.logLines.push_back(oss.str()); // 输出到底层流 logger.outputStream << value; } return logger; } // 处理有符号整数 friend Logger& operator<<(Logger& logger, int value) { if (logger.currentSeverity >= logger.loggerSeverity) { std::ostringstream oss; oss << logger.outputStream.flags() << value; logger.logLines.push_back(oss.str()); logger.outputStream << value; } return logger; }如果需要支持
long、long long等其他数值类型,按照同样的模式添加重载即可。额外注意点
- 必须包含
<iostream>和<sstream>头文件,否则会出现类型未定义的错误。 - 如果不需要在
logLines中记录格式化后的数值内容,可以省略std::ostringstream相关的逻辑,直接输出到底层流即可。
- 必须包含
内容的提问来源于stack exchange,提问作者binaryBigInt
相关产品推荐
相关产品推荐

