提问人:TheEagle 提问时间:8/29/2023 更新时间:8/29/2023 访问量:71
枚举类的运算符<<不起作用
operator<< for enum class just doesn't work
问:
我有以下代码:
日志记录.hxx
#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());
logging.cxx
#include "logging.hxx"
std::ostream& operator<<(std::ostream& s, FGaugeLogger::LogLevel level) {
s << "level";
return s;
}
main.cxx
#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 我的代码与这个类似问题的答案中的第三个示例相同。
答:
3赞
Jan Schultke
8/29/2023
#1
问题是 C++ 文件是从上到下解析的,事情的顺序通常很重要。在你写的地方:
std::cerr << "[" << level << "] " << msg << std::endl;
for 尚未声明。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);
// ...
};
您还可以在类中定义它,使其成为隐藏的友元(请参阅隐藏的友元:声明和定义)。
替代解决方案
您也可以在定义 之后定义 out-of-line,例如log
operator<<
template<typename T>
void FGaugeLogger::log(LogLevel level, const T& msg) { /* ... */ }
但是,与第一个解决方案相比,这总体上需要更多的工作,后者只需要您将代码移动到类中并使其 .外行定义成员函数模板需要一些代码重复。friend
评论
public Singleton<FGaugeLogger>
template<typename T> void FGaugeLogger::log(LogLevel level, const T& msg)
std::ostream& operator<<(std::ostream& s, const FGaugeLogger::LogLevel level);
ss << (expr);