I am trying to figure out how to decorate a std::function with "before" and "after" hooks.
I have some trouble figuring out the right syntax. This is what I have so far:
// create a "before" hook
template<typename Functor, typename Hook>
Functor hook_before(const Functor & original, Hook hook)
{
// not legal, but illustrates what I want to achieve
template<typename Args ...args>
return [=](Args ...args)
{
hook();
original(args...);
};
}
My sample application is on Ideone.
Can anyone help me figure it out?
You can do it like so:
#include <functional>
#include <iostream>
template <class Hook, class ReturnType, class... ArgType>
std::function<ReturnType(ArgType...)> hook_before(
const std::function<ReturnType(ArgType...)>& original,
Hook hook)
{
return [=](ArgType... args){
hook();
return original(std::move(args)...);
};
}
int main()
{
std::function<int(int, int)> sum = [](int a, int b) { return a + b; };
std::cout << sum(3, 4) << std::endl;
auto myhook = []() { std::cout << "Calculating sum" << std::endl; };
auto hooked_sum = hook_before(sum, myhook);
std::cout << hooked_sum(3, 4) << std::endl;
}
The hook_before function accepts two functors, and returns another that accepts the same arguments as the first (the ArgType parameter pack), but calls hook first.
Here goes (untested):
template <typename HOOK, typename RET, typename... ARGS>
struct BeforeHook {
std::function<RET(ARGS...)> functor;
HOOK hook;
BeforeHook(blah) : blah {};
RET operator()(ARGS&&... args) const {
hook();
return functor(args...);
}
};
template <typename HOOK, typename RET, typename... ARGS>
BeforeHook<HOOK, RET, ARGS...> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
return BeforeHook<HOOK, RET, ARGS...>(original, hook);
}
Usage:
auto hooked = hook_before(original_functor, hook_functor);
hooked(args_for_original_functor); // calls hook_functor, then original_functor
Or something along those lines. The original_functor needs to be convertible to std::function, but pretty much everything callable is. Both functors need to be cost-callable, but you could remove the const from operator() if you like.
If you want to experiment with returning a lambda rather than an instance of BeforeHook, use the same trick with the template arguments RET and ...ARGS, and find out whether it's possible to use a template argument pack in a lambda:
template <typename HOOK, typename RET, typename... ARGS>
std::function<RET(ARGS...)> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
return [=](ARGS&&... args) -> RET {
hook();
return original(args...);
};
}
Either way, I think the key trick is using std::function in a template argument deduction to separate the return type from the arguments.
Try the following.
template<typename Functor, typename Hook>
struct BeforeHooked
{
Functor f;
Hook hook;
template<class... Args>
typename std::result_of<F(Args&&...)>::type
operator()(Args&&... args)
{
hook();
return f(std::forward<Args&&>(args)...);
}
};
template<typename Functor, typename Hook>
Functor hook_before(Functor f, Hook hook)
{
return BeforeHooked{f, hook};
}
The code is untested, but assuming you have a compiler which can compile it, I think it should do what you want. Unlike the other answers, it can accept any functor, not just std::function, and if you give it a polymorphic functor it remains polymorphic.
Related
I implemented a Visit function (on a variant) that checks that the currently active type in the variant matches the function signature (more precisely the first argument). Based on this nice answer.
For example
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v){
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data)) {
std::cerr<< "alternative mismatch\n";
return;
}
v(std::get<Arg1>(data));
}
int main(){
Visit([](const int& i){std::cout << i << "\n"; });
Visit([](const std::string& s){std::cout << s << "\n"; });
// Visit([](auto& x){}); ugly kabooom
}
This works, but it explodes with a user unfriendly compile time error when users passes a generic (e.g. [](auto&){}) lambda. Is there a way to detect this and give nice static_assert() about it?
Would also be nice if it worked with function templates as well, not just with lambdas.
Note that I do not know what possible lambdas do, so I can not do some clever stuff with Dummy types since lambdas may invoke arbitrary functions on types.
In other words I can not try to call lambda in 2 std::void_t tests on int and std::string and if it works assume it is generic because they might try to call .BlaLol() on int and string.
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator() type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool{} )
{ return true; }
constexpr bool foo (...)
{ return false; }
int main()
{
auto l1 = [](int){ return 0; };
auto l2 = [](auto){ return 0; };
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
}
Instead of a bool, you can return std::true_type (from foo() first version) or std::false_type (from second version) if you want to use it through decltype().
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()s: when there is a single, non template, operator(), you should get 1 from foo(); otherwise (no operator(), more than one operator(), template operator()), foo() should return 0.
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v) {
class Auto {};
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
}
The Auto class is just an invented type impossible to occur in the V parameters. If V accepts Auto as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x){}); // nice static assert
Visit([](auto *x){}); // nice static assert
Visit([](auto &x){}); // nice static assert
Visit([](auto &&x){}); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type {};
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type{};
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type{};
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v){
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
{
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
{
std::cerr<< "alternative mismatch\n";
return;
}
v(std::get<Arg1>(data));
}
else
{
std::cout << "it's a template / auto lambda " << std::endl;
}
}
template <class T>
void foo(const T& t)
{
std::cout <<t << " foo \n";
}
void fooi(const int& t)
{
std::cout <<t << " fooi " << std::endl;
}
int main(){
Visit([](const int& i){std::cout << i << std::endl; });
Visit([](const std::string& s){std::cout << s << std::endl; });
Visit([](auto& x){std::cout <<x << std::endl;}); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
}
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
I'm implementing simple text formatter for a class. The main function in it could receive a list of values that will be concatenated. Or optionally, for cases where the parameters are not friends of ostream, I accept a conversion function as first parameter that will convert all other parameters into a std::string.
The following code shows the idea, but it does not compile. For simplicity, I will output to cout in the example.
struct formater{
template<typename P, typename... PS>
void format(const P& p, const PS&... ps){
if (std::is_convertible<P, std::function<void()>>::value){
cout << p(ps...) << endl;
} else {
cout << p;
log(ps...);
}
}
};
The reason the code does not compile is, if P is callable, it will not be possible to output it to cout in the "else" branch, and if P is not callable, it will tell P is not callable and cannot receive ps... parameters in the "then" branch.
I thought to use enable_if, but since I'm defining both cases (T and F) of the condition, I get redefinition of same function and also fail to compile.
I could try to mimic static_if, but it doesn't look elegant at all.
I'm wondering if there is some elegant way to check that P is callable and SFINAE it. Maybe exploiting that I know the parameter types of P, (PS...)->std::string.
There are two problems. First, just like you said, an if is a runtime branch only, and second, you are not checking for an object to be callable, but you are checking if an object is callable with no arguments. Any callable object that must take arguments won't pass your test.
I would first implement that trait. Note that this is not necessary for C++17:
template<typename, typename = void>
struct is_callable : std::false_type {};
template<typename F, typename... Args>
struct is_callable<F(Args...), void_t<decltype(std::declval<F>()(std::declval<Args>()...))>> : std::true_type {};
Then, you can use std::enable_if:
struct Formatter {
template<typename F, typename... Args>
auto format(F func, Args&&... args) -> std::enable_if_t<is_callable_v<F(Args...)>> {
std::cout << func(std::forward<Args>(args)...);
std::cout << std::endl;
}
template<typename T>
auto format(T&& value) -> std::enable_if_t<!is_callable_v<T()>> {
std::cout << std::forward<T>(value);
std::cout << std::endl;
}
};
You can implement void_t like this:
template<typename...>
using void_t = void;
You can go check this live example: Live at coliru
Please note that in C++17, you have the constexpr if and std::is_invocable:
struct Formatter {
template<typename F, typename... Args
void format(F&& param, Args&&... args) {
if constexpr (std::is_invocable_v<F, Args...>) {
std::cout << std::invoke(std::forward<F>(param), std::forward<Args>(args)...);
} else {
std::cout << std::forward<F>(param);
log(std::forward<Args>(args)...);
}
}
};
You could use std::enable_if:
struct formater{
template<typename P, typename... PS>
std::enable_if<std::is_convertible<PARAM, std::function<void(PS...)>>::value, void>::type
format(const PARAM& p, const PS&... ps){
cout << p(ps...) << endl;
}
template<typename P, typename... PS>
std::enable_if<!std::is_convertible<PARAM, std::function<void(PS...)>>::value, void>::type
format(const PARAM& p, const PS&... ps){
cout << p;
log(ps...);
}
};
I have a template class that must perform some operation before calling a function whose parameters and return type are generic.
This is the method:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
ReturnType rv = makeCall(args...); // [1]
// dismiss the call
// ...
return rv;
}
Of course it's compiling correctly when ReturnType is not void.
When I use it in this context:
function<void>(firstArg, secondArg);
The compiler responds with
error: return-statement with a value, in function returning 'void' [-fpermissive]
pointing to the line marked with [1].
Is there any solution other than passing -fpermissive to the compiler?
I would prefer to have a unique method, because I possible solution I found is to instantiate different versions using enable_if and is_same.
Thank you in advance.
-- Update --
This is a complete example. I should have said that our functions are indeed class methods.
#include <type_traits>
#include <iostream>
class Caller {
public:
Caller() {}
template <typename ReturnType, typename ...Arguments>
ReturnType call(Arguments ... args) {
prepare();
ReturnType rv = callImpl<ReturnType>(args...);
done();
return rv;
}
private:
void prepare() {
std::cout << "Prepare\n";
}
void done() {
std::cout << "Done\n";
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, void>::value, ReturnType>::type callImpl ( Arguments ... args) {
std::cout << "Calling with void\n";
return;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, bool>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with bool\n";
return true;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, int>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with int\n";
return 42;
}
};
int main(int argc, char *argv[]) {
Caller c;
auto rbool = c.call<bool> (1,20);
std::cout << "Return: " << rbool << "\n";
auto rint = c.call<int> (1,20);
std::cout << "Return: " << rint << "\n";
// the next line fails compilation. compile with --std=c++11
c.call<void>("abababa");
return 0;
}
-- Update --
Not a big issue: Use std::bind(&Caller::callImpl<ReturnType>, this, args).
Here's my attempt at a general C++11-compliant solution that you can easily reuse.
Let's start by creating a simple type trait that converts void to an empty struct. This doesn't introduce any code repetition.
struct nothing { };
template <typename T>
struct void_to_nothing
{
using type = T;
};
template <>
struct void_to_nothing<void>
{
using type = nothing;
};
template <typename T>
using void_to_nothing_t = typename void_to_nothing<T>::type;
We also need a way to call an arbitrary function converting an eventual void return type to nothing:
template <typename TReturn>
struct helper
{
template <typename TF, typename... Ts>
TReturn operator()(TF&& f, Ts&&... xs) const
{
return std::forward<TF>(f)(std::forward<Ts>(xs)...);
}
};
template <>
struct helper<void>
{
template <typename TF, typename... Ts>
nothing operator()(TF&& f, Ts&&... xs) const
{
std::forward<TF>(f)(std::forward<Ts>(xs)...);
return nothing{};
}
};
template <typename TF, typename... Ts>
auto with_void_to_nothing(TF&& f, Ts&&... xs)
-> void_to_nothing_t<
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...))>
{
using return_type =
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...));
return helper<return_type>{}(std::forward<TF>(f), std::forward<Ts>(xs)...);
}
Usage:
template <typename ReturnType, typename ...Args>
void_to_nothing_t<ReturnType> function (Args ...args) {
// prepare for call
// ...
auto rv = with_void_to_nothing(makeCall, args...); // [1]
// dismiss the call
// ...
return rv;
}
live wandbox example
There's a proposal by Matt Calabrese called "Regular Void" that would solve this issue. You can find it here: "P0146R1".
Depending on what you wish to accomplish in the lines
// dismiss the call
you might be able to use:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
CallDismisser c;
return makeCall(args...); // [1]
}
That would work as long as the destructor of CallDismisser can do everything you need to do.
struct nothing {};
template<class Sig>
using returns_void = std::is_same< std::result_of_t<Sig>, void >;
template<class Sig>
using enable_void_wrap = std::enable_if_t< returns_void<Sig>{}, nothing >;
template<class Sig>
using disable_void_wrap = std::enable_if_t< !returns_void<Sig>{}, std::result_of_t<Sig> >;
template<class F>
auto wrapped_invoker( F&& f ) {
return overload(
[&](auto&&...args)->enable_void_wrap<F(decltype(args)...)> {
std::forward<F>(f)(decltype(args)(args)...);
return {};
},
[&](auto&&...args)->disable_void_wrap<F(decltype(args)...)> {
return std::forward<F>(f)(decltype(args)(args)...);
}
);
}
so wrapped_invoker takes a function object, and makes it return nothing instead of void.
Next, holder:
template<class T>
struct holder {
T t;
T&& get()&& { return std::forward<T>(t); }
};
template<>
struct holder<void> {
template<class T>
holder(T&&) {} // discard
void get()&& {}
};
holder lets you hold the return value and convert back to void if needed. You must create holder<T> using {} to get reference lifetime extension to work properly. Adding a ctor to holder<T> will break it.
holder<void> silently discards anything passed to it.
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
holder<ReturnType> rv{ wrapped_invoker(makeCall)(args...) };
// dismiss the call
// ...
return std::move(rv).get();
}
Now, holder<ReturnType> holds either nothing or the return value of makeCall(args...).
If it holds nothing, rv.get() returns void, and it is legal to return void to a function where ReturnValue is void.
Basically we are doing two tricks. First, we are preventing makeCall from returning void, and second if we are returning void we are discarding the return value of makeCall conditionally.
overload isn't written here, but it is a function that takes 1 or more function objects (such as lambdas) and returns their overload set. There is a proposal for std::overload, and a myriad of examples on stackoverflow itself.
Here is some:
Overloaded lambdas in C++ and differences between clang and gcc
C++11 “overloaded lambda” with variadic template and variable capture
The problem seems to be with //Dismiss the call.
This code shouldn't exist. That's what we have RAII for. The following code does work, even with ReturnType = void.
template <typename ReturnType, typename ...Arguments>
ReturnType call(Arguments ... args) {
Context cx;
return callImpl<ReturnType>(args...);
}
Context::Context() { std::cout << "prepare\n"; }
Context::~Context() { std::cout << "done\n"; }
I got this piece of code:
template <class FunctionType> class Entry {
std::function<FunctionType> internalFunction;
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...)){
if (std::is_same<decltype(internalFunction(arguments...)), void>::value) {
internalFunction(arguments...);
} else {
auto result = internalFunction(arguments...);
return result;
}
}
};
Entry class is meant to be wrapper for std::function. It works for all return types with one exception - void. I can't get it to work. I have also tried std::is_void, it doesn't return true for function of type void(...). The same for std::is_same.
How to get around this problem?
return internalFunction(arguments...);
That works even if internalFunction returns void
Trying to store the result in an intermediate object doesn't work, because you can't create an object of type void, because it's not an object type.
Your if doesn't work, because if is a run time condition, the compiler still needs to compile both branches of the condition and so they must both be valid C++.
If you need to create a variable of the intermediate result type then you cannot use that code for the void case. You can write a partial specialization for functions returning void:
template <class FunctionType> class Entry {
std::function<FunctionType> internalFunction;
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...))
{
auto result = internalFunction(arguments...);
return result;
}
};
template <class... ArgTypes> class Entry<void(ArgTypes...)> {
std::function<void(ArgTypes...)> internalFunction;
template<class... Arguments>
void operator()(Arguments... arguments) {
internalFunction(arguments...);
}
};
That would not work for functions returning void but not for functors that return void, doing that is a bit harder.
It follows another solution, that one based on sfinae instead of partial specialization.
I tried to provide a minimal, complete example.
I'd also have introduced the perfect forwarding in the example, but it would have been pretty different from the one in the question, so I decided to leave it more similar to that one.
#include<functional>
#include<type_traits>
template <class FunctionType> class Entry {
std::function<FunctionType> internalFunction;
template<typename R, typename... Args>
typename std::enable_if<std::is_void<R>::value>::type
invoke(Args... args) {
internalFunction(args...);
}
template<typename R, typename... Args>
typename std::enable_if<not std::is_void<R>::value, R>::type
invoke(Args... args) {
return internalFunction(args...);
}
public:
Entry(std::function<FunctionType> f)
: internalFunction{f} { }
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...)){
return invoke<typename std::function<FunctionType>::result_type>(arguments...);
}
};
int f() { return 42; }
void g() { }
int main() {
Entry<int()> e1(&f);
e1();
Entry<void()> e2(&g);
e2();
}
For further details about sfinae see here.
Is it possible to store a parameter pack somehow for a later use?
template <typename... T>
class Action {
private:
std::function<void(T...)> f;
T... args; // <--- something like this
public:
Action(std::function<void(T...)> f, T... args) : f(f), args(args) {}
void act(){
f(args); // <--- such that this will be possible
}
}
Then later on:
void main(){
Action<int,int> add([](int x, int y){std::cout << (x+y);}, 3, 4);
//...
add.act();
}
To accomplish what you want done here, you'll have to store your template arguments in a tuple:
std::tuple<Ts...> args;
Furthermore, you'll have to change up your constructor a bit. In particular, initializing args with an std::make_tuple and also allowing universal references in your parameter list:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
Moreover, you would have to set up a sequence generator much like this:
namespace helper
{
template <int... Is>
struct index {};
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> {};
}
And you can implement your method in terms of one taking such a generator:
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
And that it! So now your class should look like this:
template <typename... Ts>
class Action
{
private:
std::function<void (Ts...)> f;
std::tuple<Ts...> args;
public:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}
template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}
void act()
{
func(args);
}
};
Here is your full program on Coliru.
Update: Here is a helper method by which specification of the template arguments aren't necessary:
template <typename F, typename... Args>
Action<Args...> make_action(F&& f, Args&&... args)
{
return Action<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}
int main()
{
auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3);
add.act();
}
And again, here is another demo.
You can use std::bind(f,args...) for this. It will generate a movable and possibly copyable object that stores a copy of the function object and of each of the arguments for later use:
#include <iostream>
#include <utility>
#include <functional>
template <typename... T>
class Action {
public:
using bind_type = decltype(std::bind(std::declval<std::function<void(T...)>>(),std::declval<T>()...));
template <typename... ConstrT>
Action(std::function<void(T...)> f, ConstrT&&... args)
: bind_(f,std::forward<ConstrT>(args)...)
{ }
void act()
{ bind_(); }
private:
bind_type bind_;
};
int main()
{
Action<int,int> add([](int x, int y)
{ std::cout << (x+y) << std::endl; },
3, 4);
add.act();
return 0;
}
Notice that std::bind is a function and you need to store, as data member, the result of calling it. The data type of that result is not easy to predict (the Standard does not even specify it precisely), so I use a combination of decltype and std::declval to compute that data type at compile time. See the definition of Action::bind_type above.
Also notice how I used universal references in the templated constructor. This ensures that you can pass arguments that do not match the class template parameters T... exactly (e.g. you can use rvalue references to some of the T and you will get them forwarded as-is to the bind call.)
Final note: If you want to store arguments as references (so that the function you pass can modify, rather than merely use, them), you need to use std::ref to wrap them in reference objects. Merely passing a T & will create a copy of the value, not a reference.
Operational code on Coliru
This question was from C++11 days. But for those finding it in search results now, some updates:
A std::tuple member is still the straightforward way to store arguments generally. (A std::bind solution similar to #jogojapan's will also work if you just want to call a specific function, but not if you want to access the arguments in other ways, or pass the arguments to more than one function, etc.)
In C++14 and later, std::make_index_sequence<N> or std::index_sequence_for<Pack...> can replace the helper::gen_seq<N> tool seen in 0x499602D2's solution:
#include <utility>
template <typename... Ts>
class Action
{
// ...
template <typename... Args, std::size_t... Is>
void func(std::tuple<Args...>& tup, std::index_sequence<Is...>)
{
f(std::get<Is>(tup)...);
}
template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, std::index_sequence_for<Args...>{});
}
// ...
};
In C++17 and later, std::apply can be used to take care of unpacking the tuple:
template <typename... Ts>
class Action
{
// ...
void act() {
std::apply(f, args);
}
};
Here's a full C++17 program showing the simplified implementation. I also updated make_action to avoid reference types in the tuple, which was always bad for rvalue arguments and fairly risky for lvalue arguments.
I think you have an XY problem. Why go to all the trouble to store the parameter pack when you could just use a lambda at the callsite? i.e.,
#include <functional>
#include <iostream>
typedef std::function<void()> Action;
void callback(int n, const char* s) {
std::cout << s << ": " << n << '\n';
}
int main() {
Action a{[]{callback(13, "foo");}};
a();
}