Note: this question uses C 20, and I'm using Visual Studio 2022 (v17.2.2).
I would like to create a template function wrapper to allow me to use std::format style logging. The wrapper function will eventually do some other non-format related stuff that is not important here.
Refer to the code below. Note that Log1() works fine, but feels clunky to use. Log2() is ok, but using std::vformat() loses compile-time checking of log format strings.
What I really want to do is Log3(). Problem is that Visual Studio (v17.2.2) doesn't like this.
Is there any way I can get this to work (without macros)?
#include <iostream>
#include <format>
#include <string_view>
// works fine: usage is clunky
auto Log1(std::string_view sv)
{
std::cout << sv;
}
// works, but fmt string is checked at runtime - not compile time
template<typename... Args>
auto Log2(std::string_view fmt, Args&&... args)
{
std::cout << std::vformat(fmt, std::make_format_args(args...));
}
// this doesn't work
template<typename... Args>
auto Log3(std::string_view fmt, Args&&... args)
{
std::cout << std::format(fmt, std::forward<Args>(args)...);
}
int main()
{
Log1(std::format("Hello, {}\n", "world!")); // ok - clunky
Log2("Hello, {}\n", "world!"); // ok - no compile time checking of fmt string
Log2("Hello, {:s}\n", 42); // ok - throws at runtime
Log3("Hello, {}\n", "world!"); // ERROR: doesn't compile
return 0;
}
CodePudding user response:
You need P2508 (my paper) to land, which exposes the currently exposition-only type std::basic-format-string<charT, Args...>
, which will allow you to write:
template<typename... Args>
auto Log3(std::format_string<Args...> fmt, Args&&... args)
Until then, you can just be naughty and use the MSVC implementation's internal helper for this, with understanding that they can rename this type at will at any point.
template<typename... Args>
auto Log3(std::_Fmt_string<Args...> fmt, Args&&... args)