Getting undeclared args when trying to bind std::function using parameter pack - c++

I'm trying to create a variadic template class that looks like this :
template <class... Args>
class Message
{
private:
std::function<void(Args...)> _function;
public:
//stuff
};
I want to have an option to bind so the user can bind any function (with corresponding arguments) when he wants. I've tried this approach (this function is a part of the Message class, so Args... comes from the template argument of the class):
template<class T>
void Message::bindFunction(void(T::*function)(Args... args), T* ownerPtr)
{
//This doesn't work
_function = boost::bind(function,args, ownerPtr);
}
However the above doesn't work, I've tried to create the tuple from the args in the bind function, but the compiler keeps saying:
<args_0> undeclared identifier.
(If I pass more arguments it changes)
From the user's point of view it should look like this:
class Foo
{
public:
void test2(int a, float b, double c)
{
std::cout << "bla";
}
};
int main()
{
Foo f;
Message<int,float,double> Mess;
Mess.bindFunction(&Foo::test2, &f);
}
I've seen a lot of articles talking about forwarding the parameters, however most of the answers confuse me more than I am already with different template structures without explaining them.

Use a lambda because they're much nicer (Live Demo (C++11)):
template<class T>
void bindFunction(void(T::*function)(Args...), T* ownerPtr)
{
_function = [function, ownerPtr](Args... args)
{
(ownerPtr->*function)(args...);
};
}
We are capturing the function pointer and pointer to instance of the class with [function, ownerPtr] in the lambda declaration.
The lambda accepts a list of arguments whose types are specified in the variadic template for the Message class: Args... args.
Internally we call the function using our instance with the (ownerPtr->*function) syntax, and then pass in the arguments by expanding the parameter pack (args...)
To call the function you might write something like this:
void callFunction(Args&&... args)
{
_function(std::forward<Args>(args)...);
}
We use perfect forwarding to pass our arguments to the std::function<void(Args...)> member.

Related

Strange error while expanding parameter pack containing lambda types

I have a function which looks like foo in the following example:
template <typename... Parameters>
void foo(std::function<void (Parameters &)>... functions) {
// does interesting things with these functions
}
Now I want to call this function with some lambdas, e.g. like this:
foo([](const std::string & string) {});
Unfortunately that doesn't work, because I get the following error:
error: no matching function for call to 'foo'
note: candidate template ignored: could not match 'function<void (type-parameter-0-0 &)>' against '(lambda at file.cpp:50:23)'
AFAIK, that is, because lambdas cannot be implicitly converted to std::functions like that.
One way to solve this problem is to manually wrap the lambdas in std::function like so:
foo(std::function<void (const std::string &)>([](const auto & string) {}));
But for multiple lambdas this would get very tedious.
To get around this problem, I tried to create a wrapper function which detects the parameter type of the lambdas it gets passed using a helper type, and then wraps the lambda in the correct std::function type. Here is this wrapper function for only a single parameter (i.e. not variadic):
template <typename Function>
void fooWrapped(Function && function) {
foo(std::function<void (typename FunctionTypeTraits<Function>::ParameterType &)>(function));
}
The helper type FunctionTypeTraits is implemented like this:
template <typename Function>
class FunctionTypeTraits:
public FunctionTypeTraits<decltype(&std::remove_reference<Function>::type::operator())> {};
template <typename Param>
class FunctionTypeTraits<void (&)(Param &)> {
typedef Param ParameterType;
};
Now I can call the wrapper function with my lambda and the compiler is perfectly happy:
fooWrapped([](const std::string & string) {});
In principle, I should now be able to make fooWrapper variadic like so:
template <typename... Functions>
void fooWrapped(Functions &&... functions) {
foo((std::function<void (typename FunctionTypeTraits<Functions>::ParameterType &)>(functions))...);
}
That doesn't work however. If I call this new function with the exact same code, I get the following error:
error: 'std::remove_reference<void ((lambda at file.cpp:50:23)::*)(const std::string &) const>::type' (aka 'void ((lambda at file.cpp:50:23)::*)(const std::string &) const') is not a class, namespace, or enumeration
I don't quite understand this error. Why does the same approach work for a single template type, but not for an expanded parameter pack? Is this maybe just a compiler bug?
Is there another way, I could achieve my goal of calling foo using lambdas, without manually wrapping each of them in a std::function?
The type of address of lambda's operator() is void (Lambda::*)(Param&) const not void (&)(Param &), you need to define the base case of your FunctionTypeTraits as:
template <typename Function>
struct FunctionTypeTraits:
public FunctionTypeTraits<decltype(&std::remove_reference<Function>::type::operator())> {};
template <typename Lambda, typename Param>
struct FunctionTypeTraits<void (Lambda::*)(Param) const> {
typedef Param ParameterType;
};
Another point is that in your fooWrapped, the type of specify for std::function should be void (typename FunctionTypeTraits<Function>::ParameterType) instead of just ParameterType since the latter is not a function type:
template <typename... Function>
void fooWrapped(Function&&... function) {
foo(std::function<void (typename FunctionTypeTraits<Function>::ParameterType)>(function)...);
}
Demo.

How to capture variadic arguments with lambda and pass them to inner scope

I have the following structure that lets me bind the virtual functions of ExampleInterfaceClass to a class that implements the virtual functions from ExampleInterfaceClass:
struct ExampleStruct {
ExampleInterfaceClass *instance = nullptr;
ExampleInterfaceClass *(*InstantiateScript)(void);
void (*DestroyScript)(ExampleStruct *);
template <typename T> void Bind(void)
{
InstantiateScript = []()
{
return static_cast<ExampleInterfaceClass *>(new T());
};
DestroyScript = [](ExampleStruct *exampleStruct)
{
delete exampleStruct->instance;
exampleStruct->instance = nullptr;
};
}
};
Now I want to forward variadic arguments from Bind() to the instantiation of the class that implement the interface. I know I have to change the template to the following
template <typename T, typename... T_args> void Bind(T_args &&... args)
But I have trouble to pass the variadic arguments to the instantiation of the class because of the lambda.
Without the lambda I think I could use the following:
return static_cast<ExampleInterfaceClass *>(new T(std::forward<T_args>(args)...));
But the compiler tells me that 'args' are not captured.
How can I capture the variadic arguments and forward them?
You can capture variadic arguments in the same way you would capture any other arguments. However, care must be taken to not capture them by value, as it will make them const qualified. Here is an example:
#include <utility>
struct L {};
void k(L&& );
template<class... T> void foo(T&&... t)
{
auto l = [&t...]() { k(std::forward<T>(t)...); };
}
void a()
{
L l{};
foo(l); // errror
foo(L{}); // OK
}
Please note, once you start capturing in lambda (no matter how), it is no longer convertible to function pointer and you'd have to store it in std::function object if you need to type-erase it.

Variadic-templated class: support void without specializing the whole class?

I have a class:
template <typename ...Arguments>
class CSignalConnection
{
public:
CSignalConnection(std::function<void(Arguments...)> target) : m_target(target) {}
void invoke(Arguments&&... args) const
{
m_target(std::forward<Arguments>(args)...);
}
private:
std::function<void(Arguments...)> m_target;
};
I want to be able to declare CSignalConnection<void> and call invoke with no arguments. And I want to avoid specializing, i. e. duplicating the whole class, when I only have a couple void-incompatible methods (like invoke here which should be declared with 0 arguments). I have a couple more classes like this so I hate to write everything twice (and edit in two places).
One idea I have is to write both void and non-void invoke overloads and disable one with SFINAE, but I don't know how to actually implement this.
Using CSignalConnection<> will make the Arguments pack empty. The following works for me
void f() {
std::cout << "hello world\n";
}
int main () { {
CSignalConnection<> cs{&f};
cs.invoke();
}
However, since you have no type deduction this is a misuse of forwarding, you'll need to make invoke() deduce the types of its arguments to get real universal references (forwarding references)
template <typename ...Arguments>
class CSignalConnection {
public:
template <typename... Ts>
void invoke(Ts&&... args) const
{
m_target(std::forward<Ts>(args)...);
}
//... rest of the class omitted ...
};

How to pass a method pointer as a template parameter

I am trying to write a code that calls a class method given as template parameter. To simplify, you can suppose the method has a single parameter (of an arbitrary type) and returns void. The goal is to avoid boilerplate in the calling site by not typing the parameter type. Here is a code sample:
template <class Method> class WrapMethod {
public:
template <class Object>
Param* getParam() { return &param_; }
Run(Object* obj) { (object->*method_)(param_); }
private:
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<Method>, 1>::type Param;
Method method_;
Param param_
};
Now, in the calling site, I can use the method without ever writing the type of the parameter.
Foo foo;
WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar;
foo_bar.GetParam()->FillWithSomething();
foo_bar.Run(foo);
So, this code works, and is almost what I want. The only problem is that I want to get rid of the BOOST_TYPEOF macro call in the calling site. I would like to be able to write something like WrapMethod<Foo::Bar> foo_bar instead of WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar.
I suspect this is not possible, since there is no way of referring to a method signature other than using the method signature itself (which is a variable for WrapMethod, and something pretty large to type at the calling site) or getting the method pointer and then doing typeof.
Any hints on how to fix these or different approaches on how to avoid typing the parameter type in the calling site are appreciated.
Just to clarify my needs: the solution must not have the typename Param in the calling site. Also, it cannot call FillWithSomething from inside WrapMethod (or similar). Because that method name can change from Param type to Param type, it needs to live in the calling site. The solution I gave satisfies both these constraints, but needs the ugly BOOST_TYPEOF in the calling site (using it inside WrapMethod or other indirection would be fine since that is code my api users won't see as long as it is correct).
Response:
As far as I can say, there is no possible solution. This boil down to the fact that is impossible to write something like WrapMethod<&Foo::Bar>, if the signature of Bar is not known in advance, even though only the cardinality is necessary. More generally, you can't have template parameters that take values (not types) if the type is not fixed. For example, it is impossible to write something like typeof_literal<0>::type which evalutes to int and typeof_literal<&Foo::Bar>::type, which would evaluate to void (Foo*::)(Param) in my example. Notice that neither BOOST_TYPEOF or decltype would help because they need to live in the caling site and can't be buried deeper in the code. The legitimate but invalid syntax below would solve the problem:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
In C++0x, as pointed in the selected response (and in others using BOOST_AUTO), one can use the auto keyword to achieve the same goal in a different way:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);
Write it as:
template <typename Object, typename Param, void (Object::*F)(Param)>
class WrapMethod {
public:
Param* getParam() { return &param_; }
void Run(Object* obj) { (obj->*F)(param_); }
private:
Param param_;
};
and
Foo foo;
WrapMethod<Foo, Param, &Foo::Bar> foo_bar;
foo_bar.getParam()->FillWithSomething();
foo_bar.Run(foo);
EDIT: Showing a template function allowing to do the same thing without any special template wrappers:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param))
{
Param param;
param.FillWithSomthing();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar);
2nd EDIT: Modifying the template function to take the initialization function as a parameter as well:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param), void (Param::*init)())
{
Param param;
param.*init();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar, &Param::FillWithSomething);
If your compiler supports decltype, use decltype:
WrapMethod<decltype(&Foo::Bar)> foo_bar;
EDIT: or, if you really want to save typing and have a C++0x compliant compiler:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar= GetWrapMethod(&Foo::Bar);
EDIT2: Although, really, if you want it to look pretty you either have to expose users to the intricacies of the C++ language or wrap it yourself in a preprocessor macro:
#define WrapMethodBlah(func) WrapMethod<decltype(func)>
Have you considered using method templates?
template <typename T> void method(T & param)
{
//body
}
Now the compiler is able to implicitly determine parameter type
int i;
bool b;
method(i);
method(b);
Or you can provide type explicitly
method<int>(i);
You can provide specializations for different data types
template <> void method<int>(int param)
{
//body
}
When you are already allowing BOOST_TYEPOF(), consider using BOOST_AUTO() with an object generator function to allow type deduction:
template<class Method> WrapMethod<Method> makeWrapMethod(Method mfp) {
return WrapMethod<Method>(mfp);
}
BOOST_AUTO(foo_bar, makeWrapMethod(&Foo::Bar));
Okay let's have a go at this.
First of all, note that template parameter deduction is available (as noted in a couple of answers) with functions.
So, here is an implementation (sort of):
// WARNING: no virtual destructor, memory leaks, etc...
struct Foo
{
void func(int e) { std::cout << e << std::endl; }
};
template <class Object>
struct Wrapper
{
virtual void Run(Object& o) = 0;
};
template <class Object, class Param>
struct Wrap: Wrapper<Object>
{
typedef void (Object::*member_function)(Param);
Wrap(member_function func, Param param): mFunction(func), mParam(param) {}
member_function mFunction;
Param mParam;
virtual void Run(Object& o) { (o.*mFunction)(mParam); }
};
template <class Object, class Param>
Wrap<Object,Param>* makeWrapper(void (Object::*func)(Param), Param p = Param())
{
return new Wrap<Object,Param>(func, p);
}
int main(int argc, char* argv[])
{
Foo foo;
Wrap<Foo,int>* fooW = makeWrapper(&Foo::func);
fooW->mParam = 1;
fooW->Run(foo);
Wrapper<Foo>* fooW2 = makeWrapper(&Foo::func, 1);
fooW2->Run(foo);
return 0;
}
I think that using a base class is the native C++ way of hiding information by type erasure.

Non-type template parameter... that's a template! (C++)

I'm basically looking to generate a wrapper for a generic C function without having to manually specify the types. So I have a callback with a fixed prototype but I'm going to need to do some special code in the wrapper based on the type of the wrapped function... So basically I'm thinking about using a static method in a class template to wrap my function to a conforming interface e.g.:
// this is what we want the wrapped function to look like
typedef void (*callback)(int);
void foobar( float x ); // wrappee
// doesn't compile
template< T (*f)(S) > // non-type template param, it's a function ptr
struct Wrapper
{
static void wrapped(int x)
{
// do a bunch of other stuff here
f(static_cast<S>(x)); // call wrapped function, ignore result
}
}
And then I'd like to do something like:
AddCallback( Wrapper<foobar>::wrapped );
However, the problem is that I can't just go ahead and use a "S" in the parameter of the function in the Wrapper template, I have to first list it as a parameter:
template< class T, class S, T (*f)(S) >
struct Wrapper
// ...
But this means it's a lot more painful to use (Wrapper<void,float,foobar>::wrapped), ideally I'd like to just pass in the function pointer there and have it work out the types of the parameters (and return types) automatically. To be clear, inside the wrapped function I'm going to need to refer to the types of the function pointer (so I do need some equivalent of S or T).
Is there a way of doing this?
One thing you might wish to consider is using LLVM or similar to generate an appropriate trampoline function at runtime. Or here's a static solution:
#include <iostream>
void f(float f) { std::cout << f << std::endl; }
template<typename T, typename S> struct static_function_adapter {
template<T(*f)(S)> struct adapt_container {
static void callback(int v) {
f(static_cast<S>(v));
}
};
template<T(*f)(S)> adapt_container<f> adapt() const {
return adapt_container<f>();
}
};
template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) {
return static_function_adapter<T, S>();
}
#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback)
int main() {
void (*adapted)(int) = ADAPTED_FUNCTION(f);
adapted(42);
return 0;
}
The get_adapter function allows us to infer the argument and return type; adapt() then converts this into a type parameterized on the actual function, and finally we get a static function in callback.
If you use a function that returns the "wrapped" rather than referring to it directly, the compiler will attempt to automatically match the template parameters for the function call.
edit: What about this?
int foobar( float x ); // wrappee
template <typename T, typename S>
struct Wrapper {
typedef T (*F)(S);
F f;
Wrapper(F f) : f(f) { }
void wrapped(S x) {
// do a bunch of other stuff here
f(x); // call wrapped function, ignore result
}
};
template <typename T, typename S>
Wrapper<T,S> getWrapper(T (*f)(S)) {
return Wrapper<T,S>(f);
}
...
getWrapper(foobar).wrapped(7);
EDIT: completely new answer
OK, I've completely re-thought the question and believe that I get what you want. I've actually done this before :-P.
Here's the idea, I have a Base class which overloads operator(), then I have a subclass for each "arity" of functions. Finally I have a factory function which will return one of these things. The code is big (and probably a little overkill) but works nicely. Much of the library_function overloads are to support different syntaxes, mostly unnecessary. It also supports boost::bind functions, member functions, etc, very much more than you probably need.
http://pastebin.com/m35af190
Example, usage:
// map of library functions which will return an int.
std::map<std::string, LibraryFunction<int> > functions;
// function to register stuff in the map
void registerFunction(const std::string &name, LibraryFunction<int> func) {
functions.insert(std::make_pair(name, func));
}
later you can do this:
// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out
// register 2 functions, one with no params, one with 1 param
registerFunction("my_function", library_function1(*this, call_my_function));
registerFunction("my_function2", library_function0(*this, call_my_function2));
functions["my_function"]();
functions["my_function2"]();
I'd look at boost. At first reading of your question, it seems to me than <boost/function_types/parameter_types.hpp> provides what your need.