I am using the spdlog library in a C++20 project using modules.
I've encapsulated spdlog inside my singleton logger class because I don't want spdlog exposed to clients in case I swap it out for a different log library someday. But now I want a macro that will call my singleton's "Trace()" method when not in the distribution configuration and be a no-op in Distribution. My macro is defined like this in Log.h:
#if defined(TS_DEBUG) || defined(TS_RELEASE)
#define TS_LOG_TRACE(...) ::ThreeSpace::Logger::Trace(__VA_ARGS__)
#else
#define TS_LOG_TRACE(...)
#endif
The macro then would forward the arguments to my public logger method. My method would simply pass those arguments on to spdlog's trace() method, which has the following signature:
template<typename... Args>
inline void trace(format_string_t<Args...> fmt, Args &&...args);
Clients would use it like this:
TS_LOG_TRACE("First value is {} and second value is {}", 42, 45);
I am having a heck of a time figuring out how to write my Logger singleton's trace() method.
I tried
template<typename... Args>
void Logger::Trace(std::format_string<Args...> fmt, Args &&...args)
{
GetInstance()->trace(fmt, std::forward<Args>(args)...);
}
but it gives me the error
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
I feel like I'm close but can't figure it out. What am I doing wrong?
Thanks for the help!
Edit: So I've discovered that if I define the templated method like this:
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;
}
it works and prints the expected message to the console. But if I change the body of the method to this, it fails:
GetInstance()->trace(fmt, std::forward<Args>(args)...);
Due to @HolyBlackCat's suggestion in the comments below, I tried:
template<typename... Args>
void Logger::Trace(fmt::format_string<Args...> fmt, Args &&...args)
{
Get()->trace(fmt, std::forward<Args>(args)...);
}
I get this error:
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