I'm trying to do something that simplifies to the following:
#include <functional>
#include <initializer_list>
#include <vector>
template <typename Ret, typename... Args>
struct func_wrapper
{
public:
using Func = std::function<Ret(Args...)>;
Ret operator()(Args && ...args)
{
return _impl(std::forward<Args>(args)...);
}
void another_function(int another_arg, Args && ...args) { }
/// and so on
private:
Func _impl;
};
func_wrapper<void(int, float)> f;
Basically, I want to make a type that wraps a std::function
and adds some other functionality for my application. Inside my type, I would like to be able to use the return type Ret
and argument parameter pack Args
freely in the class interface. However, when I try to compile the above with gcc 8.3, I get an error:
<source>: In instantiation of 'struct func_wrapper<void(int, float)>':
<source>:20:32: required from here
<source>:9:45: error: function returning a function
using Func = std::function<Ret(Args...)>;
^
<source>:11:9: error: function returning a function
Ret operator()(Args && ...args)
I'm not sure what to make of that error. Is there a straightforward way to do what I want?
The problem is that you have to use partial specialization
template <typename>
struct func_wrapper;
template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
{
// ...
};
If you write
template <typename Ret, typename... Args>
struct func_wrapper
{
// ...
};
declaring f
as
func_wrapper<void(int, float)> f;
you have that Ret
is deduced as void(int, float)
and the Args...
variadic list is deduced as an empty list.
So, when you define
using Func = std::function<Ret(Args...)>;
the Func
declaration become
// ............................V..........VVV function-function type ?
using Func = std::function<void(int, float)()>;
that gives the "error: function returning a function" error.
You have to declare func_wrapper
as receiving a single typename
template <typename>
struct func_wrapper;
so you can pass the type of the function (void(int, float)
in your example) as template parameter, and then a template specialization
template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
{
// ...
};
can resolve return type and arguments types from the function type.