Вы не можете сделать это таким образом.
Если вы используете в функции аргументы variadi c, лучшее, что вы можете сделать, - это преобразовать эти аргументы в кортеж.
Однако один кортеж отличается от любого другого кортежа с любым другим списком аргументов, поэтому вы не можете сохранить его в контейнере для последующего обратного вызова.
Если кортежи были получены из Общий базовый класс, вы сможете хранить их до использования (это должно go через слой двойной диспетчеризации с virtual call()
методом). Это не очень удобно писать, так как это подразумевает почти переписывание типа std::tuple
.
На вашем месте я бы сделал наоборот, то есть сделал бы лямбду, которая вызывает обратный вызов, и передал он преобразован в std::function
в контейнере для последующего вызова.
Что-то в этом псевдокоде (не проверено):
template <typename F, typename... Args>
void registerCallback(F f, Args&&... args)
{
// Make a function that's calling the callback and store that instead
std::function<void()> laterCB = [&] { f(args...); };
// Simply store in your std::vector<std::function<void()>> container
Store::getInstance().addSubscriber(laterCB);
}
void triggerCB()
{
for (auto i : Store::getInstance().getCB())
*i();
}
Еще одно замечание:
Этот вид кода всегда очень небезопасен, поскольку тип аргументов может быть ссылочным (в синтаксисе нет ничего, что могло бы помешать этому). При обратном вызове указанный объект может больше не существовать. Если вам нужно написать библиотеку, вам лучше не делать этого, а вместо этого сделать свой интерфейс очень жестким, чтобы предотвратить это.
Пример небезопасного использования:
// DON'T DO THAT
struct A { ... };
int processA(A & a) {
a.foo();
}
if (something())
{
A a;
yourLib.registerCallback(processA, a);
}
// Calls processA with a reference on a
// destructed object 'a' => so it'll crash
yourLib.triggerCB();