我有以下代码:
#include <iostream>
#include <string>
#include <sstream>
#include "singleton.hxx"
#include "utils.hxx"
class FGaugeLogger: public Singleton<FGaugeLogger> {
public:
enum class LogLevel: int {
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3,
FATAL = 4,
};
FGaugeLogger() {};
template<typename T>
void log(LogLevel level, const T& msg) {
if (level >= _level) {
if (level >= LogLevel::WARNING) {
std::cerr << "[" << level << "] " << msg << std::endl;
} else {
std::cout << "[" << level << "] " << msg << std::endl;
}
}
}
private:
LogLevel _level {LogLevel::DEBUG};
};
std::ostream& operator<<(std::ostream& s, const FGaugeLogger::LogLevel level);
#define LOG(level, expr) \
std::stringstream ss; \
ss << expr; \
std::string str = ss.str(); \
FGaugeLogger::instance()->log(FGaugeLogger::LogLevel::level, ss.str());
#include "logging.hxx"
std::ostream& operator<<(std::ostream& s, FGaugeLogger::LogLevel level) {
s << "level";
return s;
}
#include "logging.hxx"
int main(int argc, char* argv[]) {
LOG("info message");
return 0;
}
编译时会给出以下消息,然后是 100 个都不匹配的重载:
In file included from /media/frederic/WD-5TB/.fg/Programme/fgauge/src/main.cxx:1:
/media/frederic/WD-5TB/.fg/Programme/fgauge/src/logging.hxx: In member function ‘void FGaugeLogger::log(FGaugeLogger::LogLevel, const T&)’:
/media/frederic/WD-5TB/.fg/Programme/fgauge/src/logging.hxx:27:58: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘FGaugeLogger::LogLevel’)
27 | std::cerr << "[" << level << "] " << msg << std::endl;
| ~~~~~~~~~~~~~~~~ ^~ ~~~~~
| | |
| | FGaugeLogger::LogLevel
| std::basic_ostream<char>
你知道这里可能出什么问题吗? AFAICS 我的代码与类似问题的答案中的第三个示例相同。
问题是 C++ 文件是从上到下解析的,而且顺序通常很重要。在你写的地方:
std::cerr << "[" << level << "] " << msg << std::endl;
operator<<
的 FGaugeLogger::LogLevel
尚未定义。
一个简单的修复方法是将其声明为类内的
friend
:
class FGaugeLogger: public Singleton<FGaugeLogger> {
public:
enum class LogLevel: int {
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3,
FATAL = 4,
};
// note: parameter names are optional, and it's probably better to omit them
friend std::ostream& operator<<(std::ostream&, FGaugeLogger::LogLevel);
// ...
};