我在一个使用模块的C++20项目中使用spdlog库。
我将spdlog封装在我的单例日志记录器类中,因为我不希望spdlog暴露给客户端,以防有一天我将它换成不同的日志库。但是现在我想要一个宏,当不在分发配置中时,它将调用我的单例的“Trace()”方法,并且在分发中是一个空操作。我的宏在Log.h中是这样定义的:
#if defined(TS_DEBUG) || defined(TS_RELEASE)
#define TS_LOG_TRACE(...) ::ThreeSpace::Logger::Trace(__VA_ARGS__)
#else
#define TS_LOG_TRACE(...)
#endif
字符串
然后,宏会将参数转发给我的公共记录器方法。我的方法只是将这些参数传递给spdlog的trace()方法,该方法具有以下签名:
template<typename... Args>
inline void trace(format_string_t<Args...> fmt, Args &&...args);
型
客户会这样使用它:
TS_LOG_TRACE("First value is {} and second value is {}", 42, 45);
型
我花了很长时间才弄清楚如何编写Logger单例的trace()方法。
我试过了
template<typename... Args>
void Logger::Trace(std::format_string<Args...> fmt, Args &&...args)
{
GetInstance()->trace(fmt, std::forward<Args>(args)...);
}
型
但它给了我错误
Error C2664: 'void spdlog::logger::trace<_Ty,_Ty>
fmt::v9::basic_format_string<char,int,int>,_Ty &&,_Ty &&)':
cannot convert argument 1 from 'std::basic_format_string<char,int,int>' to
'fmt::v9::basic_format_string<char,int,int>'
ThreeSpace C:\Dev\ThreeSpace\Core\src\Logger.cppm 90
型
我觉得我很接近了,但我想不出来。我做错了什么?
谢谢你的帮助!
Edit:所以我发现如果我像这样定义模板化方法:
template<typename... Args>
void Logger::Trace(std::format_string<Args...> fmt, Args &&...args)
{
std::string str = std::format(fmt, std::forward<Args>(args)...);
std::cout << str;
}
型
它工作并将预期的消息打印到控制台。但是如果我将方法的主体改为这样,它就会失败:
GetInstance()->trace(fmt, std::forward<Args>(args)...);
型
由于@HolyBlackCat在下面评论中的建议,我尝试了:
template<typename... Args>
void Logger::Trace(fmt::format_string<Args...> fmt, Args &&...args)
{
Get()->trace(fmt, std::forward<Args>(args)...);
}
型
我得到这个错误:
2>C:\Dev\ThreeSpace\ThreeSpace\src\Main.cppm(21): fatal error C1116: unrecoverable error importing module 'Logger'. Specialization of 'std::unique_ptr<spdlog::formatter,std::default_delete<spdlog::formatter>>::unique_ptr' with arguments 'spdlog::pattern_formatter, std::default_delete<spdlog::pattern_formatter>, 0'
2>C:\Dev\ThreeSpace\ThreeSpace\src\Main.cppm(21,1): message : see reference to class template instantiation 'std::is_convertible<spdlog::pattern_formatter *,_Ty *>' being compiled
2> with
2> [
2>C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(544,5): error MSB6006: "CL.exe" exited with code 2.
2> _Ty=spdlog::formatter
2> ]
2>C:\Dev\ThreeSpace\ThreeSpace\src\Main.cppm(21): message : see reference to variable template 'const bool conjunction_v<std::negation<std::is_array<spdlog::pattern_formatter> >,std::is_convertible<spdlog::pattern_formatter *,spdlog::formatter *>,std::is_convertible<std::default_delete<spdlog::pattern_formatter>,std::default_delete<spdlog::formatter> > >' being compiled
型
1条答案
按热度按时间dgenwo3n1#
正如@HolyBlackCat在最初的问题中所建议的那样,我确实让我的原始代码与常规头文件(传统的非基于模块的C++)一起工作,但我最终找到了问题所在,并让它与模块一起工作:
在我的Log.h中,我刚刚定义了宏:
字符串
我的主模块(Main.cppm)看起来像这样:
型
如果你编译它,你会得到一个神秘的错误:
型
事实证明,如果我回到Log. h文件并在其中包含spdlog/pattern_formatter. h文件,错误就会消失:
型
这对我来说似乎很奇怪,因为spdlog的使用完全是模块内部的(我封装它的全部原因)。对于为什么需要它,我最好的猜测是因为可变参数宏扩展为一个接受
fmt::format_string<T>
的模板化成员函数,因此需要在转换单元中声明(通过Log. h文件)。我需要找出在
pattern_formatter.h
文件中可以提取哪些内容,以使预处理/编译器负载保持最小。