Template functor with any parameters - c++

I'm trying to create template functor, which will take as arguments object and member function with any number of parameters. I can't figure out how to write the code correctly with templates.
template<typename ItemT,
class T,
typename ...Args>
struct Builder
{
ItemT operator()(T& object, ItemT (T::*method)(Args...), Args && ... args)
{
return (object.*method)(std::forward<Args>(args)...);
}
};
struct Object
{
int method(int, int, int) { return 4; }
};
int main()
{
Object obj;
Builder<int, Object>()(obj, &Object::method); // Error here
}
If I make Object::method with no parameters - code compiles. But with parameters - no.
Severity Code Description Project File Line Suppression State
Error C2664 'int Builder::operator ()(T &,ItemT (__thiscall Object::* )(void))': cannot convert argument 2 from 'int (__thiscall Object::* )(int,int,int)' to 'int (__thiscall Object::* )(void)' drafts c:\drafts\main.cpp 139

Assuming you don't want to change the current definition of Builder, this is how you need to instantiate it:
Builder<int, Object, int, int, int>()(obj, &Object::method, 0, 0, 0);
// ^ ^ ^^^^^^^^^^^^^ ^^^^^^^
// ItemT | | |
// T Args... args...
The args... parameter expansion in the operator() call must match the TArgs... pack passed to Builder itself.
wandbox example
Here's an alternative less strict design:
template<typename T>
struct Builder
{
template <typename TFnPtr, typename... Args>
auto operator()(T& object, TFnPtr method, Args && ... args)
{
return (object.*method)(std::forward<Args>(args)...);
}
};
The above Builder can be used like this:
int main()
{
Object obj;
Builder<Object>()(obj, &Object::method, 0, 0, 0);
}
In this case the type of member function pointer is deduced through TFnPtr and not constrained to any particular set of parameters. The variadic parameters are not part of Builder anymore - they're part of Builder::operator(), so they can be deduced and forwarded to (object.*method).
wandbox example

You can avoid templating on Builder altogether and solely rely on template argument deduction:
struct Builder {
template <typename Obj, typename R, typename ... FArgs, typename ... Args>
R operator()(Obj& obj, R (Obj::*fn)(FArgs...), Args&&... args) {
return (obj.*fn)(std::forward<Args>(args)...);
}
};
I chose to use two parameter packs to allow perfect forwarding: the value categories of the operator() call do not necessarily match the targeted method. This also allows for implicit conversion of arguments when applying the member function pointer. Note that this implementation will not match const methods of Obj.
You can of course relax it a bit using auto return type (C++14) or trailing return type (C++11). Since Vittorio's answer already presented you the C++14 way, I'll tackle the latter. The operator() then becomes:
template <typename Obj, typename FnPtr, typename ... Args>
auto operator()(Obj& obj, FnPtr fn, Args&&... args)
-> decltype((obj.*fn)(std::forward<Args>(args)...)) {
return (obj.*fn)(std::forward<Args>(args)...);
}
Then, usage will simply be:
Object obj;
Builder()(obj, &Object::method, 0, 0, 0);
live demo on Coliru.

Related

Deducing template parameters from std::function

I'm writing a little class using a static template member function trying to map a std::function with its parameters :
class test
{
public:
template <typename R, typename... Args>
static double exec(std::function<R(Args...)> func, Args && ... args) {
func(std::forward<Args>(args)...);
// do something
return 0.0;
}
};
Supposing I have these trivial functions :
void f1() { ; }
int f2(int v) { return v; }
double f3(int v1, float v2) { return (double)v1 * (double)v2; }
I would like to call my test::exec function like this :
test::exec(f1);
test::exec(f2, 4);
test::exec(f3, 1, 3.14f);
I'm using Visual Studio and I get this error for the second case (f2) :
error C2672: 'test::exec': no matching overloaded function found
error C2784: 'double test::exec(std::function<_Ret(_Types...)>,Args &&...)': could not deduce template argument for 'std::function<_Ret(_Types...)>' from 'int (__cdecl *)(int)'
Nevertheless, it work if I specify the the types in the template signature : test::exec<int, int>(sq, 4); Obviously, I would like to avoid that. Also, I don't know how to formulate the call to f1 with this syntax.
Is it possible to achieve this goal without specifying the signature of the template parameters?
The compiler can't deduce the std:function arguments and return type, because you are not passing exec a std::function at all.
Instead of a std::function, you can just make exec accept an arbitrary type of callable (which includes functions), and let the compiler deduce its signature:
template <typename Func, typename... Args>
static double exec(Func func, Args && ... args);
If you do need to know the return type of the function that you pass to exec, you can do it like this:
template <typename Func, typename... Args>
static double exec(Func func, Args && ... args)
{
using R = decltype(func(args...));
// ...
}
The answer is adapted from #IgorTandetnik's comments.

Deducing function overload in a templated function

I'm writing my own std::async analogue (has to work back to Intel13/gcc 4.4 STL), and this works fine:
template <typename Func, typename ...Args>
struct return_value {
template <typename T>
using decayed = typename std::decay<T>::type;
using type = typename std::result_of<decayed<Func>(decayed<Args>...)>::type;
};
template <typename Func, typename ...Args>
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
return func(args...);
}
void run(int a, double b) {
printf("a: %i b: %f\n", a, b);
}
int main() {
async(run, 1, 3.14);
}
But if I add an overload for run:
void run() {
printf("no args\n");
}
Then it can't properly resolve:
<source>: In function 'int main()':
<source>:27:23: error: no matching function for call to 'async(<unresolved overloaded function type>, int, double)'
async(run, 1, 3.14);
^
<source>:14:43: note: candidate: 'template<class Func, class ... Args> typename return_value<Func, Args>::type async(Func&&, Args&& ...)'
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
^~~~~
<source>:14:43: note: template argument deduction/substitution failed:
<source>:27:23: note: couldn't deduce template parameter 'Func'
async(run, 1, 3.14);
^
Compiler returned: 1
How can I take a function as a template parameter and properly deduce the overload given the arguments?
I personally don't see a way to disambiguate overloads unless you know the return type. You could assume return type void most common and to this then: (I am simplifying your example for brevity)
template <class F, class... Args>
auto async(F f, Args... args)
{
return f(args...);
}
template <class... Args>
auto async(void (*f)(Args...), Args... args)
{
return f(args...);
}
void run();
void run(int, double);
auto test()
{
async(run); // calls run();
async(run, 1, 2.); // calls run(int, double);
}
This does seem kind of fishy and confusing to the user. Why does it work when the function passed returns void and it doesn't if it returns int? So I don't recommend it.
So really the only thing you could do is let it in the hands of the user to figure it out.
So some solutions for the caller of your function:
The good (and ugly) old way: use cast to disambiguate the overload:
async(static_cast<int(*)(int, double)>(run), 1, 2.);
I personally don't like this approach at all. I don't like the verbosity of it and most of all I don't like that I have to be explicit about something that should really be implicit.
The lambda way
async([] { return run(1, 2.); });
I like this. It's not half bad. Still a little bit verbose, but way way better than other alternatives.
The macro way
Yes, macros, in C++. Without further ado, there it is (perfect forwarding omitted for brevity):
#define OVERLOAD(foo) [] (auto... args) { return foo(args...); }
async(OVERLOAD(run), 1, 2.);
I am not going to comment on this one. I leave each and every one of you to judge this macro.

Template variadic function in template class won't compile

I'm trying to write a function for a template class which takes in a parameter that is a function pointer for a member class inside the private data of the big class. When you call that member, it calls that function on smaller class. (Confusing right?) To demonstrate, I have a non-working example here:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
Please note that this isn't my actual code but a small example of what I'm trying to do. As you can see, I'm trying to call the size member function of the 'Private' (I have kept it public here for demonstration) vector class inside MyClass. This only works whenever I have no parameters for the compiler to unpack, but when I try to do the insert function (which has parameters to unpack), the compiler gives me an error of:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
This is the same error I'm getting in my actual production code, calling the variadic function with no parameters to unpack works, but if I give more than that, I get the same error message. This is my first real attempt to use Variadic templates, so any recommendation and help will be appreciated.
The problem here is that insert is an overloaded function. The compiler is not doing to try and resolve what overload you want in template argument deduction as there is no way for it to know. You have to cast the function to the type of the overload you want to use in order to give it a type. That would look like
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
In general it is
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
Another option would be to change the function a little and take a lambda that expresses what you want done. That would look like
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
Basically you cannot take address of an unresolved overloaded function, because the compiler won't be able to choose the right function entry point address. During normal function call the compiler resolves overloaded function, but with templates like yours or std::bind() this won't work, because the parameters are used to call the template function, not the function you want to take address of.
You can manually resolve the overload like this:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
It's easier to deal in function objects when doing this kind of thing. It offloads the problem of method overloads to the compiler.
Lambdas also work (they're function objects):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}

Perfect-forward non-T arguments while converting T-s

(This question follows from this answer)
I am trying to adapt a trampoline function that is currently just passing through a variable number of arguments.
I would like to have it convert any argument PyObject* pyob to Object{pyob}, but forward all other arguments through.
So (void* self, int, PyObject*, float) -> (int, Object, float)
In that example, the first self argument is stripped away. This always happens. Out of the remaining arguments, one of them is of type PyObject*, and hence requires conversion to Object.
Here is the function:
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R
call(void* s, Args... args)
{
std::cout << "trap:" << typeid(t).name() << std::endl;
try
{
return (get_base(s)->*t)(std::forward<Args>(args)...);
}
catch (...)
{
std::cout << "CAUGHT" << std::endl;
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}
};
It appears not to be forwarding arguments. I think it is making a copy of each argument. I've tried:
call(void* s, Args&&... args)
But that just generates compiler errors.
The complete test case is here
How can I fix the function to perfect-forward all arguments apart from those of type PyObject*, which it should convert?
It appears not to be forwarding arguments
You can't perfectly-forward arguments of a function which is not a template, or which is invoked through a pointer to a function, like you do. Perfect-forwarding involves a template argument deduction, which doesn't take place when you invoke a function through a pointer - that pointer points to a concrete instantiation of a function template.
The std::forward<Args>(args) expression is there to possibly utilize a move-constructor to copy-initialize the parameters of the target function from those arguments of call that are passed by value (or by a hard-coded rvalue reference), or let them be bound by an rvalue reference - you won't need any more those instances, you are free to move-from them, saving at least one copy operation. (It could be as simple as static_cast<Args&&>(args)..., because it's just a reference collapsing).
I would like to have it convert any argument PyObject* pyob to Object{pyob}, but forward all other arguments through. How can I fix the function to perfect-forward all arguments apart from those of type PyObject*, which it should convert?
#include <utility>
template <typename T, typename U>
T&& forward_convert(U&& u)
{
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Object forward_convert(PyObject* a)
{
return Object{a};
}
// ...
return (get_base(s)->*t)(forward_convert<Args>(args)...);
To replace any occurrence of Object with PyObject* while creating the signature of call function, and only then conditionally forward or convert the arguments, you should do what follows:
template <typename T>
struct replace { using type = T; };
template <>
struct replace<Object> { using type = PyObject*; };
// you may probably want some more cv-ref specializations:
//template <>
//struct replace<Object&> { using type = PyObject*; };
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R
call(void* s, typename replace<Args>::type... args)
{
try
{
return (get_base(s)->*t)(forward_convert<typename replace<Args>::type>(args)...);
}
catch (...)
{
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}
};
DEMO
You have to change call to (Note that I introduce Ts in addition to Args).
template <typename ... Ts>
static R
call(void* s, Ts&&... args)
{
std::cout << "trap:" << typeid(t).name() << std::endl;
try
{
return (get_base(s)->*t)(std::forward<Ts>(args)...);
}
catch (...)
{
std::cout << "CAUGHT" << std::endl;
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}

bindParameter function with variadic templates in C++11

I'm trying to write a simple function to convert a std::function<> object while binding the last parameter(s). That's what I've got:
template<typename R, typename Bind, typename ...Args> std::function<R (Args...)> bindParameter (std::function<R (Args..., Bind)> f, Bind b)
{
return [f, b] (Args... args) -> R { return f (args..., b); };
}
And that's how I'd like to use it:
int blub (int a, int b)
{
return a * b;
}
// ...
int main ()
{
std::function<int (int, int)> f1 (blub);
// doesn't work
std::function<int (int)> f2 = bindParameter (f1, 21);
// works
std::function<int (int)> f3 = bindParameter<int, int, int> (f1, 21);
return f2 (2);
}
... so that in this example the main function should return 42. The problem is, that gcc (4.6) doesn't seem to infer the types of the template parameters correctly, the first version produces the following errors:
test.cpp:35:58: error: no matching function for call to 'bindParameter(std::function<int(int, int)>&, int)'
test.cpp:35:58: note: candidate is:
test.cpp:21:82: note: template<class R, class Bind, class ... Args> std::function<R(Args ...)> bindParameter(std::function<R(Args ..., Bind)>, Bind)
But in my opinion the parameters are obvious. Or is this kind of type inference not covered by the standard or not yet implemented in gcc?
You can't use std::function as a deduced parameter of a function template. Deduction can't work in this fashion as there are no rules to match int(*)(int, int) to std::function<int(int, int)>. (Consider also that for any std::function<Signature> there is a constructor accepting int(*)(int, int), even if in most cases this results in an error when instantiated.)
It's problematic to detect the signature of functor in the general case. Even KennyTM's solution has limitations: it detects the signature of monomorphic functors and function-like things, but won't work for polymorphic functors (e.g. with overloaded operator()) or functors with surrogate call functions (even in the monomorphic case).
It is however possible to completely sidestep the issue of detecting the signature thanks to decltype (or equivalently, std::result_of), and I would recommend doing so. Hence, a variant on KennyTM's answer:
template<typename Functor, typename Bound>
struct bind_last_type {
Functor functor;
Bound bound;
template<typename... Args>
auto operator()(Args&&... args)
-> typename std::result_of<Functor&(Args..., Bound)>::type
// equivalent:
// -> decltype( functor(std::forward<Args>(args)..., std::move(bound)) )
{ return functor(std::forward<Args>(args)..., std::move(bound)); }
};
template<typename Functor, typename Bound>
bind_last_type<
typename std::decay<Functor>::type
, typename std::decay<Bound>::type
>
bind_last(Functor&& functor, Bound&& bound)
{ return { std::forward<Functor>(functor), std::forward<Bound>(bound) }; }
Not sure about the inference, but it works if I just define a templated function object.
template <typename FType, typename LastArgType>
struct BindLastHelper
{
FType _f;
LastArgType _last_arg;
template <typename... Args>
typename utils::function_traits<FType>::result_type
operator()(Args&&... args) const
{
return _f(std::forward<Args>(args)..., _last_arg);
}
};
template<typename FType, typename LastArgType>
BindLastHelper<FType, LastArgType> bindParameter (FType f, LastArgType b)
{
return BindLastHelper<FType, LastArgType>{f, b};
}
Note:
utils::function_traits is taken from https://github.com/kennytm/utils/blob/master/traits.hpp. std::result_of cannot be used because you are not passing a function pointer.
Proof of concept: http://ideone.com/ux7YY (here for simplicity I just redefined result_of.)