I am trying to create a basic logger. Here is a small example.
template<typename ...str>
struct log {
log(
str &&...args,
const char *file = __builtin_FILE(),
const char *func = __builtin_FUNCTION(),
const size_t line = __builtin_LINE()
) {
std::cout << "[" << file << "] [" << func << "] [" << line << "] ";
((std::cout << args << " "), ...);
std::cout << std::endl;
}
};
template<typename ...str>
log(str &&...args) -> log<str ...>;
I want the ability to receive caller information along with a variable number of arguments. With the above example, I can create an instance like this.
log inst("THIS WORKS", "ASD", "ASD");
>>> [.../main.cpp] [main] [10] THIS WORKS ASD ASD
I also want the ability to specify logging levels. This is where the trouble begins. Say I have an enum with the following logging levels, and I want to make it a template argument for the logger. The following is how I thought this would work.
enum logging_level {
INFO,
};
template<logging_level level, typename ...str>
struct log {
...
};
template<logging_level level, typename ...str>
log(str &&...args) -> log<level, str ...>;
log<INFO> inst("THIS DOESN'T WORK", "ASD", "ASD");
The error I get here is that the arguments are passed into the default arguments, not the variadic arguments.
>>> error: invalid conversion from ‘const char*’ to ‘size_t’ {aka ‘long unsigned int’} [-fpermissive]
>>> 33 | log<INFO> inst("THIS DOESN'T WORK", "ASD", "ASD");
>>> | ^~~~~
>>> | |
>>> | const char*
This is getting well above my C++ template knowledge. An easy solution is to ditch the variadic template and just pass in a string but I wanted to see if this could work. Does anyone know how to make this compile?
Thanks.