mercredi 16 septembre 2020

storing templated parameter pack in std::function object

I have developed a library which is used in other libraries and applications. Its up for the application to provide the actual logging facility. The library shall only define a set of verbosity levels and pass the message to the application if something happened that should be logged. Hence my idea is to store a std::function object in my library that actually points to some callback in the client application. Note in prior that C style variadic template arguments accessed via va_start, va_list and va_end are no option. This is because the client may use a non-printf based scheme such as spdlog does as an example. I am aware of not providing a MWE but that is because the code does not even compile.

library:

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

client application:

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,
                                       ???);
} 

The only place in code I know about the actual type of the variadic template parameters is while logging from within the library. How can the client register for a callback he does not know the arguments for? This is the first time for me to use a parameter pack so I hope the code/idea is at least somehow reasonable. Apart from that why is it necessary to specify the variadic paramter type when calling a method on an instance of the std::function:

logging_callback<args_t...>(level, msg, std::forward<args_t>(args)...);

instead of

logging_callback(level, msg, std::forward<args_t>(args)...);

PS: cstd++11 is required, still if there is a better solution with a more recent version I am happy to hear about it too!

Aucun commentaire:

Enregistrer un commentaire