#c #templates #callback #variadic-templates
#c #шаблоны #обратный вызов #переменные-шаблоны
Вопрос:
Я хочу сохранить и передать список аргументов шаблона функции.
Like std::thread
передает аргументы потоку. Типы аргументов являются шаблонными, а количество аргументов не является статическим.
Пример, как это будет работать:
class CallbackList {
public:
Callback(/* Type of list of template args */ args) {
this->saved_args = args;
}
void Call() {
this->callback(saved_args);
}
private:
/* Type of list of template args */ saved_args;
CallbackType callback;
}
Или как я могу это реализовать:
template<typename ...Args>
class CallbackList {
public:
using CallbackPrototype = /* some prototype */;
void RegisterCallback(CallbackPrototype callback, Args... args) {
CallbackInfo callback_info;
callback_info.callback = callback;
callback_info.args = { args... };
this->callbacks.push_back(callback_info);
}
void Call() {
for (CallbackInfoamp; callback_info : this->callbacks)
callback_info.callback(callback_info.args);
}
private:
struct CallbackInfo {
CallbackPrototype callback;
/* what type should be here? tuple? args count are not static */ args;
};
std::vector<CallbackInfo> callbacks;
}
Это возможно?
Как я могу это реализовать?
Комментарии:
1. Вы согласны с созданием
Callback
шаблона класса или собираетесь хранить разные объекты обратного вызова в одном контейнере?2. вы ищете переменные шаблоны. Это широкая тема, я предлагаю вам взглянуть на некоторые примеры, например, здесь: en.cppreference.com/w/cpp/language/parameter_pack
3. Каков фактический
callback
набор? Здесь он никогда не инициализируется.4. @NathanOliver, я могу сделать класс шаблонным @AndyG, это пример,
callback
поле будет инициализировано, я также добавил второй пример, ближе к моей реальной задаче
Ответ №1:
Если вы не хотите, чтобы ваш обратный вызов зависел от типов аргументов, вы должны использовать какое-то удаление типов. Вы можете, например, использовать std::function
из <functional>
:
#include <functional>
#include <iostream>
class Lazy_Callback
{
public:
template <typename F, typename ...Args>
Lazy_Callback(F amp;amp; f, Args amp;amp; ...args)
: _fun([=]() { return f(args...); })
{ }
void call() const
{
_fun();
}
protected:
private:
std::function<void()> _fun;
};
void print_int(int x)
{
std::cout << "x = " << x << "n";
}
int main()
{
Lazy_Callback lc(print_int, 5);
lc.call();
}
Если обратный вызов может быть шаблонным, вы можете использовать std::tuple
для хранения своих аргументов:
#include <tuple>
#include <iostream>
template <typename F, typename ...Args>
class Lazy_Callback
{
public:
template <typename ...Ts>
Lazy_Callback(F f, Ts amp;amp; ...ts)
: _f(f), _args(ts...)
{ }
void call() const
{
return std::apply(_f, _args);
}
protected:
private:
F _f;
std::tuple<Args...> _args;
};
template <typename F, typename ...Ts>
Lazy_Callback<F, std::decay_t<Ts>...> make_callback(F amp;amp; f, Ts amp;amp; ...ts)
{
return { std::forward<F>(f), std::forward<Ts>(ts)... };
}
void print_int(int x)
{
std::cout << "x = " << x << "n";
}
int main()
{
auto lc = make_callback(print_int, 5);
lc.call();
}
Ответ №2:
Вы ищете что-то вроде std::bind
? Вот простой пример, который вы, вероятно, могли бы расширить:
#include <iostream>
#include <functional>
template <typename T1, typename T2>
void printSum(const T1amp; a, const T2amp; b)
{
std::cout << a b << std::endl;
}
int main()
{
const auto callback = std::bind(amp;printSum<int, int>, 1, 2);
// ...
callback();
}
Комментарии:
1. Я добавил второй пример, ближе к моей реальной проблеме. Он должен быть динамически сохранен в памяти. Это возможно?