【发布时间】:2020-08-23 18:07:26
【问题描述】:
我目前正在开发一个线程日志库,作为一个更大的图形绘制项目的第一部分(用于个人学习和技能发展)。
目前我正在使用一个单例,其中一个线程在旁边运行,并将日志消息和数据放入队列中(这样它们就不会阻塞事件)以供稍后处理。我在 std::map 周围写了一个小包装器作为 LogData,它可以由记录器以下列方式显示在流或文件中。
[0.000155][DEBUG]: FILE LOGGER ADDED { ID="1" LVL="TRACE" }
构造函数允许传递 string、char*、floats、int、short long 等,并将其转换为稍后显示在这些括号中的字符串。
目前构建这个 LogData 有点臃肿。生成上述日志的示例:
GG::LogData id_dat;
id_dat.push("ID", id);
id_dat.push("LVL",GG::loglevel_toString(lvl));
GG_DEBUG("FILE LOGGER ADDED", id_dat);
由于我的班级是单身人士,我使用宏来方便使用,它们都与:
#define GG_TRACE(MESS, ...) GG::Logging::get()->push_to_queue(GG::LOG_LEVEL::TRACE, MESS, ##__VA_ARGS__);
这适用于大多数用途。但我想让它可以在一条线上使用,并让它不那么臃肿。我想要达到的效果是这样的:
//Desired Usage
GG_TRACE("VARIADIC TEST", {"X","1"}, {"Y","2"}, {"Z","3"});
这里展开:
void Logging::push_to_queue(GG::LOG_LEVEL level, std::string mess, std::pair<const char*, std::string> log_data ...)
我会使用大括号初始化列表来生成日志数据,然后我会遍历可变参数并在函数中构造 LogData,而不必每次都手动进行。
我让它直接使用这样的函数。
void test(std::pair<char*,int> p) {
GG::LogData dat;
dat.push("key", p.first);
dat.push("value", p.second);
GG_TRACE("PAIR: ", dat);
}
// In main...
test({ "test",1 });
而且效果很好。但是,当我尝试使用相同的模式并将宏转发到 push_to_queue 函数时,我在 GCC 中收到以下错误。
有人曾经以这种方式使用过大括号括起来的初始化列表,或者知道如何修复这个错误吗?我对这种模式相当陌生。任何其他建议或改进这一点的指针表示赞赏。 (抱歉,帖子太长了)
【问题讨论】:
-
根据我的经验(使用 Google 测试),宏和大括号初始化器表现不佳。
-
错误的想法!在解析任何 c 或 c++ 代码之前处理宏。将某些东西从 c++ 传回宏是没有技巧的。顺便说一句:停止使用宏!我们在 2020 年,应该可以编写一些简单的函数,它可以根据需要采用任意数量的不同类型,
-
@Klaus 任何类型...但是大括号初始化列表没有类型,并且总是意味着为参数/参数对跳过模板参数推导,因此简单的可变参数模板不会好用,至少使用所需的语法。
-
@Klaus 有什么建议,需要调整吗?
-
@aschepler 在这种情况下你建议我做什么?坚持使用宏?任何其他模式建议?
标签: c++ macros initializer-list variadic