C++ 在std::function对象中存储模板化参数包
我开发了一个用于其他库和应用程序的库。 由应用程序提供实际的日志记录功能。库应仅定义一组详细级别,并在发生应记录的事件时将消息传递给应用程序。 因此,我的想法是在我的库中存储一个C++ 在std::function对象中存储模板化参数包,c++,c++11,logging,variadic-functions,std-function,C++,C++11,Logging,Variadic Functions,Std Function,我开发了一个用于其他库和应用程序的库。 由应用程序提供实际的日志记录功能。库应仅定义一组详细级别,并在发生应记录的事件时将消息传递给应用程序。 因此,我的想法是在我的库中存储一个std::function对象,它实际上指向客户端应用程序中的某个回调。请注意,在之前的版本中,通过va_start、va_list和va_end访问的C样式变量模板参数不是选项。这是因为客户端可能使用非基于printf的方案,例如spdlogdoes。我知道没有提供MWE,但这是因为代码甚至没有编译 图书馆: .hpp
std::function
对象,它实际上指向客户端应用程序中的某个回调。请注意,在之前的版本中,通过va_start、va_list
和va_end
访问的C样式变量模板参数不是选项。这是因为客户端可能使用非基于printf的方案,例如spdlog
does。我知道没有提供MWE,但这是因为代码甚至没有编译
图书馆:
.hpp
enum class severity_t
{
trace = 0,
debug = 1,
warn = 2,
error = 3,
critical = 4
};
template <typename ...args_t>
using logging_callback_t = std::function<void(severity_t, std::string, args_t...)>;
template <typename ...args_t>
extern logging_callback_t<args_t...> logging_callback;
template <typename ...args_t>
void log(severity_t level, const std::string& msg, args_t&& ...args)
{
logging_callback<args_t...>(level, msg, std::forward<args_t>(args)...);
}
template <typename ...args_t>
void set_logging_cbk(logging_callback_t<args_t...> func)
{
logging_callback<args_t...> = func;
}
.cpp
template <typename ...args_t>
logging_callback_t<args_t...> logging_callback;
std::string to_append("something");
log(severity_t::warn, "abc {}", to_append);
.hpp
枚举类严重性\u t
{
跟踪=0,
调试=1,
警告=2,
误差=3,
临界值=4
};
模板
使用logging\u callback\u t=std::函数;
模板
外部日志记录\u回调\u t日志记录\u回调;
模板
无效日志(严重性级别、常量标准::字符串和消息、参数和参数)
{
记录回调(级别、消息、标准::转发(args)…);
}
模板
无效集\日志\ cbk(日志\回调\函数)
{
logging_callback=func;
}
.cpp
模板
日志记录\u回调\u t日志记录\u回调;
std::字符串到_append(“某物”);
日志(severity_t::warn,“abc{}”,要追加);
客户端应用程序:
template <typename ...args_t)
void log_from_lib_a(severity_t level, const std::string& msg, args_t&& args...)
{
if(level == severity_t::warn)
{
spdlog::warn(msg, std::forward<args_t>(args)...);
}
}
int main()
{
set_logging_cbk<???>(boost::bind(&log_from_lib_a<???&...>,
boost::placeholders::_1,
boost::placeholders::_2,
???);
}
template您不能拥有虚拟模板方法,这正是您在std::function
后面的类型擦除所需要的
当您控制库时,您知道实际使用的每个原型,因此您可以创建一个符合您需要的记录器接口:
struct ILogger
{
virtual ~ILogger() = default;
virtual void write(severity_t, const std::string&) = 0;
virtual void write(severity_t, const std::string&, int) = 0;
virtual void write(severity_t, const std::string&, int, const std::string&) = 0;
virtual void write(severity_t, const std::string&, float) = 0;
// ...
};
void set_logger(ILogger&); // custom point
然后提供一种从可变函子轻松创建类的方法,如:
template <typename Functor>
struct LoggerT : ILogger, Functor
{
using Functor::Functor;
using Functor::operator();
void write(severity_t level, const std::string& format) override { (*this)(level, format);}
void write(severity_t level, const std::string& format, int v1) override { (*this)(level, format, v1);}
void write(severity_t level, const std::string& format, int v1, const std::string& v2) override { (*this)(level, format, v1, v2);}
void write(severity_t level, const std::string& format, float v1) override { (*this)(level, format, v1);}
// ...
};
template <typename Func>
LoggerT<Func> make_logger(Func func) { return {func}; }
请写信
struct ILogger
{
virtual ~ILogger() = default;
virtual void write(severity_t, const std::string&) = 0;
virtual void write(severity_t, const std::string&, int) = 0;
virtual void write(severity_t, const std::string&, int, const std::string&) = 0;
virtual void write(severity_t, const std::string&, float) = 0;
// ...
};
void set_logger(ILogger&); // custom point
template <typename Functor>
struct LoggerT : ILogger, Functor
{
using Functor::Functor;
using Functor::operator();
void write(severity_t level, const std::string& format) override { (*this)(level, format);}
void write(severity_t level, const std::string& format, int v1) override { (*this)(level, format, v1);}
void write(severity_t level, const std::string& format, int v1, const std::string& v2) override { (*this)(level, format, v1, v2);}
void write(severity_t level, const std::string& format, float v1) override { (*this)(level, format, v1);}
// ...
};
template <typename Func>
LoggerT<Func> make_logger(Func func) { return {func}; }
struct SpdLogger {
template <typename ... Ts>
void operator () (severity_t level, const std::string& msg, Ts&& args...)
{
if (level == severity_t::warn)
{
spdlog::warn(msg, std::forward<Ts>(args)...);
}
}
};
int main()
{
LoggerT<SpdLogger> logger;
set_logger(logger);
// ...
}
auto logger = make_logger([](severity_t level, const std::string& msg, auto&& args...)
{
if(level == severity_t::warn)
{
spdlog::warn(msg, decltype(args)(args)...); // decltype(args) is the forward
}
});
set_logger(logger);