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);