I'd like to create a simple log function in C++ which prepend the code location to the log message. I'd like to avoid macros overall as well as the usage of __FILE__
& __LINE__
.
Note that the format
string is always a compile-time string, and I'd like to have a much computation as possible on compile time (the target machine is a small MCU).
I can use the C++20 source_location
feature via experimental/source_location
.
I can also use {fmt}.
I started off from this. Currently, I've got the following:
#include <fmt/format.h>
#include <experimental/source_location>
using source_location = std::experimental::source_location;
void vlog(fmt::string_view format, fmt::format_args args)
{
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const S& format, const source_location& location, Args&&... args)
{
vlog(format, fmt::make_args_checked<fmt::string_view, uint32_t, Args...>(format, location.file_name(), location.line(), args...));
}
#define MY_LOG(format, ...) log(FMT_STRING("{},{}, " format), source_location::current(), __VA_ARGS__)
int main() {
MY_LOG("invalid squishiness: {}", 42);
}
Which yields correctly ./example.cpp,20, invalid squishiness: 42
.
Looks to me like I'm pretty close. I think what's left is to make the log
function take a default argument for source_location
(I understand that source_location::current()
as a default arguement is a good practice). I'm getting the following error though:
:12:99: error: missing default argument on parameter 'args'
Is this even possible to mix variadic templates and default arguments for parameters? If so, how?
Also, is there a way to prepend the "{},{}, "
part to the compile-time format
string to yield yet another compile-time string (to be used as format)?
{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.
fmt stands for the Format package. This package allows to format basic strings, values, or anything and print them or collect user input from the console, or write into a file using a writer or even print customized fancy error messages. This package is all about formatting input and output.
You can do it with a struct that represents the format string and location:
#include <fmt/core.h>
#include <source_location>
struct format_string {
fmt::string_view str;
std::source_location loc;
format_string(
const char* str,
const std::source_location& loc =
std::source_location::current()) : str(str), loc(loc) {}
};
void vlog(const format_string& format, fmt::format_args args) {
const auto& loc = format.loc;
fmt::print("{}:{}: ", loc.file_name(), loc.line());
fmt::vprint(format.str, args);
}
template <typename... Args>
void log(const format_string& format, Args&&... args) {
vlog(format, fmt::make_format_args(args...));
}
int main() {
log("invalid squishiness: {}", 42);
}
This prints:
./example.cpp:26: invalid squishiness: 42
Godbolt: https://godbolt.org/z/4aMKcW
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With