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.
Related
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.
I'm missing something very fundamental about type deduction here:
I'm attempting to write a wrapper function that calls a writer function with a nullptr to get a required length, then resizes a buffer, then calls the function again, now with the resized buffer, to get the final output. There's a large number of these writer functions, and I want to generalize the call/resize/call pattern into a variadic template function.
However, I'm stuck at trying to pass both a function pointer to a function taking the variadic args, and passing the variadic args, when any parameter in the list is a const reference:
static void val_arg(int) { }
static void ref_arg(const int&) { }
template <typename... Args>
static void helper(void (*fun)(Args...), Args... args)
{
(*fun)(args...);
}
void proxy(const int& arg)
{
helper(&val_arg, arg); // Fine
helper(&ref_arg, arg); // 'void helper(void (__cdecl *)(Args...),Args...)': template parameter 'Args' is ambiguous
// note: could be 'const int&'
// note: or 'int'
}
void test()
{
proxy(1); // Force 1 to be const int&
}
What can I do to make it transparently accept both cases? Why is it not acknowledging that the function passed in accepts a const ref, and the argument to the proxy is also a const ref?
Args... won't deduce a reference type.
template <typename Fun, typename... Args>
static void helper(Fun fun, Args&&... args)
{
fun(std::forward<Args>(args)...);
}
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;
}
I try to pass to a variadic template function a list of references and pass it to another function. The code that I wrote is the following:
template <typename T>
void fun(cv::Point_<T> & pt) { pt.x++; pt.y++; }
template <class ... args>
void caller(args & ... list) {
typedef typename std::tuple_element<0, std::tuple<args...> >::type T;
std::array<std::reference_wrapper<T>, sizeof...(list)> values {list ... };
for(int i=0; i<values.size(); i++)
fun(values[i]);
}
then I call the function caller in this way:
cv::Point2f a, b, c;
caller(a, b, c);
the compiler give me the following error:
No matching function for call to 'fun'
Candidate template ignored: could not match 'Point_' against 'reference_wrapper'
what I missing?
Although std::reference_wrapper<T> has an implicit conversion to T&, you cannot use both an implicit conversion and template argument deduction at the same time, and template argument deduction is necessary to call fun.
Try
fun(values[i].get());
Even simpler is
template <typename...Args>
void caller(Args&...args)
{
auto tmp = { (func(args),0)..., 0 };
}
This uses the fact that parameter pack expansion can occur in braced init lists. Since func() returns void, we cannot simply use { func(args)... }, but use (func(args),0) to have an int. Finally, the last 0 is to ensure that the code compiles (and does nothing) in case of an empty parameter pack.
You can generalise this and write a template that calls a given generic function for every element of a pack:
template <typename Func, typename...Args>
void call_for_each(Func &&func, Args&&...args)
{
auto unused = { (func(std::forward<Args>(args)),0)...,0 };
}
which may be used like this (C++14)
int main()
{
int a=1;
double b=2.4;
auto func = [](auto&x) { std::cout<<' '<<x++; };
call_for_each(func,a,b);
std::cout<<'\n';
call_for_each(func,a,b);
std::cout<<'\n';
}
This uses a C++14 lambda (taking an auto argument). Note that the parameter pack must come last among the template parameters of call_for_each.
Since the goal of this might be to iterate over all args, here's a more generic solution. We are going to implement for_pack:
template<typename... Args, typename F>
void for_pack(F function, Args&&... args) {
using expand = int[];
(void)expand{(function(std::forward<Args>(args)), void(), 0)..., 0};
}
This will execute function for every args in Args.
Now, your function caller is much more trivial to implement:
template <typename... args>
void caller(args&... list) {
for_pack([&](cv::Point_<T>& arg){
fun(arg);
}, list...);
}
Since a google search for "c++ pass reference parameters to variadic template" gives this as first result, I'll put this generic solution here.
struct HH { /*...*/ void change_me() { /*...*/ } };
template<typename...T> void parms_r_refs() {}
template<typename H, typename...T> void parms_r_refs(H &h, T&...t) { h.change_me(); parms_r_refs(t...); }
template<typename...T> void parms_r_refs(T&...t) { parms_r_refs(t...); }
HH a, b, c;
..
parms_r_refs(a, b, 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.