I am trying to create a composite logger which will be selected and defined at compile time.
The original implementation is using inheritance and VTable, which is causing some overhead, takes too much code and is ineffective at runtime. This is supposed to be simplification, which accepts basically any stream defined in C++ and then reference to syslog()
function, checks types and then let's compiler generate the appropriate machine code.
It works at it is supposed to, however I'd like to ask about this warning:
$ g++ -std=c++17 template_types.cpp -o asd
template_types.cpp: In function ‘int main(int, char**)’:
template_types.cpp:44:41: warning: ignoring attributes on template argument ‘void (&)(int, const char*, ...)’ [-Wignored-attributes]
44 | logger<syslog_log_t, decltype(syslog)&> C(syslog);
If I understand it correctly, logger
template should take type of the logger as first template type and the logging channel type as second template type. This allows me to move and reference the channel in the F file
variable. It can hold file descriptor in the form of std::ofstream
, as well as reference std::cout
or any other stream as well as it can work with function syslog. However the compiler g++ (Debian 9.3.0-18) 9.3.0
thinks that there is something wrong with the code. Could you please tell me, why is it thinking so? Thank you.
/* template_types.cpp */
#include <iostream>
#include <fstream>
#include <syslog.h>
/* types of logger, just for semantics */
using syslog_log_t = struct syslog_type{};
using console_log_t = struct console_type{};
using file_log_t = struct file_type{};
/* template for composite logger */
template <typename T, typename F>
class logger {
private:
F file;
public:
/* perfect forward the channel for logging as rvalue, can move and reference */
logger(F &&out) : file(std::forward<F>(out)) {};
/* if the logging channel is file, close it on end */
~logger() {
if constexpr (std::is_same_v<T, file_log_t>) {
file.close();
}
}
/* log, allows using stream and syslog call */
void log(const std::string &msg, int log_level = 0) {
if constexpr (std::is_same_v<T, syslog_log_t>) {
file(log_level, msg.c_str());
}
else {
file << msg;
}
}
};
int main(int argc, char *argv[]) {
//logger<file_log_t, std::ofstream> A(std::ofstream("text.txt", std::ios_base::out | std::ios_base::app));
std::ofstream file("text.txt", std::ios_base::out | std::ios_base::app);
logger<file_log_t, decltype(file)> A(std::move(file));
A.log("Hello\n");
logger<console_log_t, decltype(std::cout)&> B(std::cout);
B.log("COUT\n");
logger<syslog_log_t, decltype(syslog)&> C(syslog);
C.log("SYSLOG\n", LOG_DEBUG);
return 0;
}