How to make a call to a template function less verbose - c++

There is a function
template <class ...T>
void foo(std::function<void(T...)> callback);
into which I pass a callback.
I'd like to do something like
foo(bar);
where bar is, for example,
void bar(int a, long b, double c, float d);
but that gives me
error: no matching function for call to bar(void (&)(int, long int, double, float))
I have to call foo as
foo(std::function<void(int, long, double, float)>(bar));
which is too verbose. Even
foo<int, long, double, float>(bar);
would have been better.
foo(bar);
would be just ideal.
Anyway, how can I make calls to foo to be less verbose?
Edit: declaration of foo has to stay the same.

I'd write a wrapper function that translates the function pointer into a std::function wrapper:
template <typename... T>
void foo(std::function<void (T...)> f) {}
template <typename... T>
void foo(void (*f)(T...)) {
foo(std::function<void (T...)>(f));
}
foo() can then be called either way:
void bar(int,double) {}
void foo_caller() {
foo(std::function<void (int,double)>(bar));
foo(bar);
}
Addendum: Non-static member function wrapper
Same approach can be used for pointer-to-member functions — just add another overload:
template <typename C,typename... T>
void foo(void (C::*f)(T...)) {
foo(std::function<void (C *,T...)>(f));
}
Note the extra first parameter for the this pointer for the member function. Usage is similar:
struct quux {
void mf(char *,double) {}
};
void foo_caller() {
foo(&quux::mf);
}

If you know you will pass a plain function pointer to foo, and not just any C++11 lambda, you can redefine foo as:
template <class ...T>
void foo(void(*callback)(T...)) {
// .....
}
If you want to support lambdas, you can be more generic with the type
template <class LambdaType>
void foo(LambdaType callback) {
// .....
}
the downside of this approach is that if you pass something that is not a function or lambda, you will get weird template error messages coming from inside of foo.
With your original solution the compiler has problems matching T... to int, long, double, float, probably because it is a nested type.
If I told you to match void(int, double) to MyTempalte<T...> you wouldn't know that I intend to replace T... with int, double, because you don't know what MyTemplate does with its arguments. Maybe MyTemplate is doing something weird to its template arguments first?
Same, the compiler doesn't know how to match std::function template parameters to your function pointer.

In case your foo definition is not set in stone, can change it to
#include <functional>
template <class Ret, class ...T>
void foo(Ret callback(T... params))
{
}
void bar(int a, long b, double c, float d){}
int main()
{
foo(bar);
}

Related

Ambiguous call when recursively calling variadic template function overload [duplicate]

This question already has an answer here:
Function overloading: empty parameter list vs parameter pack
(1 answer)
Closed 8 months ago.
Consider this piece of code:
template<typename FirstArg>
void foo()
{
}
template<typename FirstArg, typename... RestOfArgs>
void foo()
{
foo<RestOfArgs...>();
}
int main()
{
foo<int, int, int>();
return 0;
}
It does not compile due to ambiguous call foo<RestOfArgs...>(); when RestOfArgs has only one element ({int}).
But this compiles without error:
template<typename FirstArg>
void foo(FirstArg x)
{
}
template<typename FirstArg, typename... RestOfArgs>
void foo(FirstArg x, RestOfArgs... y)
{
foo(y...);
}
int main()
{
foo<int, int, int>(5, 6, 7);
return 0;
}
Why is there ambiguity in the first case?
Why is there no ambiguity in the second case?
In Function template overloading
There is lot of rules to tell which template function is more specialized (according to given parameters).
The point which makes
template<typename> void foo();
template<typename, typename...> void foo();
ambiguous for foo<int>(), but not
template<typename T> void foo(T);
template<typename T, typename... Ts> void foo(T, Ts...);
for foo(42) is the following:
In case of a tie, if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack.
The answer by #ZangMingJie answers the difference in behavior your are observing in your code.
I found it easier to understand the name resolution with the following change:
template<typename FirstArg>
void foo()
{
printf("1\n");
}
template<typename FirstArg, typename SecondArg, typename... RestOfArgs>
void foo()
{
printf("2\n");
foo<SecondArg, RestOfArgs...>();
}
int main()
{
foo<int, int, int>();
return 0;
}
When two or more template parameters are used, the second function gets invoked. When one template parameter is used, the first function gets invoked.
Why is there ambiguity in the first case?
RestOfArgs can be empty.
So foo<int> can be instantiated as:
template<int>
void foo()
{
}
and
template<int,>
void foo()
{
foo<>();
}
both will compile, so it is ambiguous.
Actually foo<>() won't compile, but it fails in the next instantiation, so it doesn't matter.
Why is there no ambiguity in the second case?
foo<int>(7) can be instantiated as:
template<int>
void foo(int 7)
{
}
and
template<int>
void foo(int 7)
{
foo();
}
but the second one is an error, because there are no foo taking no argument, so the only candidate is the first one, so there won't be ambiguous

C++ pass function to call by template type by parameter

I have a class A that is a wrapper around a container of template objects of type T. T is expected to be a class in this use case. A has no reference whatsoever on the provided T type.
Is there a way to implement a function in A to call a function of T passed by parameters? Pseudocode:
template <class T>
void A:callFunction(functionToCall, functionParams, ...) {
objectT->functionToCall(functionParams, ...);
}
objectT is of type T, functionToCall is void
I have not been able to find if it's really impossible to do in C++98 and why. Any possible workaround would help too.
It is possible, for example:
#include <iostream>
using namespace std;
struct bar
{
void say(int a, int b)
{ cout << a << ' ' << b << endl; }
};
template <typename T>
struct foo
{
template <typename fptr>
void say(fptr f, int a, int b)
{
(i.*f)(a, b);
}
T i;
};
int main() {
foo<bar> f;
f.say(&bar::say, 10, 100);
}
(this will compile with -std=c++98 for example on gcc)
If you don't want to use a template parameter for the member function, something like;
void say(void (T::*f)(int, int), int a, int b)
{
(i.*f)(a, b);
}
Ought to work too..
As #Nim said, it's possible, as long as you know at least the number of arguments to be forwarded (types can be "templated") and define a function only for that number of arguments (or multiple functions using overloading). There's no possibility to create a function forwarder for any number of arguments.
This is only possible in C++11 using the "variadic template" feature:
template <class T, class Function, class... Args>
void A::callFunction(Function functionToCall, Args... functionParams) {
bind(objectT, functionToCall, functionParams...);
}
Note that this:
objectT->functionToCall(functionParams, ...);
is not possible at all because you cannot specify a symbol defined inside a class as a "free symbol". However you can try to exploit the "pointer to member" feature and do this:
(objectT->*functionToCall)(functionParams, ...);
as long as this "functionToCall" is a pointer to member function of the class to which's object objectT points. For example:
x->callFunction(&T::something, a, b);

C++ std::function-like template syntax

In C++11 you can instantiate std::function like this:
std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on
But while there is plenty of info on variadic templates on the web, I fail to find any articles on how to write std::function-like template which would accept parenthesized arguments.
Could anyone please explain the syntax and its limitations or at least point to an existing explanation?
There's nothing special about it, it's an ordinary function type. When you declare a function like this:
int foo(char a, double b)
Then its type is int (char, double). One way of "unwrapping" the individual argument types and return type is to use partial template specialisation. Basically, std::function looks something like this:
template <class T>
struct function; // not defined
template <class R, class... A>
struct function<R (A...)>
{
// definition here
};
Pretty much like any other template, since int(std::string, std::string) is just a type.
Here's a really naive example that compiles:
template <typename FType>
struct Functor
{
Functor(FType* fptr) : fptr(fptr) {}
template <typename ...Args>
void call(Args... args)
{
fptr(args...);
}
private:
FType* fptr;
};
void foo(int x, char y, bool z) {}
int main()
{
Functor<void(int, char, bool)> f(&foo);
f.call(1, 'a', true);
//f.call(); // error: too few arguments to function
}
In reality you'd have a specialisation on FType being ReturnType(ArgTypes...), though my naive example will already give you the validation you need if you try to invoke it in in compatible ways.

avoid specifying redundant template parameters which contain templated function pointer

Suppose we have this code:
template <class T, void (*u)(T&)>
void Foo()
{
// store the function u internally . . .
}
There are reasons to do something like this and I won't attempt to go into them. However, is there any way to avoid having to specify type T when calling Foo()? For example, to compile, one normally needs:
Foo<int, MyIntFunction>();
But if this int can be deduced from the function pointer, is this possible:
Foo<MyIntFunction>();
EDIT I'm aware of the solution to pass the actual function pointer in as a function parameter, however this is not desired here as it has some perf drawbacks in intensive loop.
In this example u is not a function pointer, it's a type (the signature of a function pointer). If you want to store a function pointer you need to pass it.
template<class T, class F = void(*)(T&)>
void Foo(F f)
{
// store the function pointer f here
}
called like so:
struct SomeType {};
void bar(SomeType& x);
Foo(&bar);
Is this what you mean to do?
Short answer: I don't think it is possible.
Long one.. When calling a template function, you cannot omit the first parameter and specify the second: the compiler would try to match your MyIntFunction to the template parameter T. Generally, you can specify the first, but omit the second if the compiler can infer the second template parameter. In this case, this is not an option however, because you want to specify the second parameter explicitly.
The second template parameter has a dependency (T) on the first template parameter. Therefore, reversing the order of the template parameters is also not an option.
Your best bet would be to define it in a way similar to what Richard suggested:
template<class T>
void Foo(T f)
{
int a(1);
f(a); // this forces f to be a function taking an int as parameter
}
Here is a dirty implementation which basically does what the OP was asking for. It depends on too many assumptions, but could be at least something to discuss. The idea is to specify in advance all possible types which can serve as function argument, and then deduce this type.
#include<iostream>
template<typename T>
struct TD; //type display
template<typename FunctionType, typename T, typename ... Ts>
struct ArgumentDeduction
{
typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
, T
, typename ArgumentDeduction<FunctionType, Ts ...>::type
>::type type;
};
template<typename FunctionType, typename T>
struct ArgumentDeduction<FunctionType, T>
{
typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
, T
, void
>::type type;
};
template<typename FunctionType
, typename T = typename ArgumentDeduction<FunctionType, int, double>::type >
void foo()
{
TD<T>();
}
struct AvoidConversion
{
struct DummyType{};
template<typename T> DummyType operator()(T x) { return DummyType(); }
};
struct Bar : public AvoidConversion
{
using AvoidConversion::operator();
void operator()(int x);
//void operator()(double x); //try also this
};
int main()
{
foo<Bar>(); //calls the foo<Bar,int> version
}
One main assumption here is the form of the Bar functor, which in principle accepts any type, but has a relevant implementation of type void only for the single allowed type.
Again, I don't think this is rather useful, but I guess this comes closest to the OP's question up to now.
DEMO
EDIT: Otherwise, i.e. without AvoidConversion in the code above, the compiler will perform an implicit conversion and the argument deduction gives true for all types which are convertible into each other (such that, e.g., int is deduced when there is only a function taking double).
If someone sees a way to avoid this ugly AvoidConversion hack and deduce the parameter type somehow more elegant, I would be interested in seeing that.

C++ pointer to template function which class member

I have the following functions in class "C"
class C
{
template<typename T> void Func1(int x);
template<typename T> void Func2(int x);
};
template<typename T> void C::Func1(int x)
{
T a(x);
}
template<typename T> void C::Func2(int x)
{
T a(x);
}
The functions uses templates only in the implementation. The signature does not contain template parameters.
Is it possible to define pointers to such template functions?
I tried the following definition but it results compilation error.
typedef template<typename T> void (СSomeClass::*TFuncPtr)(int);
Once instantiated, a member function template is just a normal member function, so you can use a normal member function pointer (best typedef'd like below):
typedef void (C::*mem_fun_ptr)(int);
mem_fun_ptr p = &C::Func1<Bar>;
// IMPORTANT -- ^^^^^
The underlined part is the important part. You can't make a pointer to a function template, but you can make a pointer to an instantiated function template.
do you want only a pointer to a function?
that's simple:
class C
{
public:
template<typename T> void Func1(int x);
};
typedef void (C::*TFuncPtr)(int);
int main()
{
TFuncPtr ptr = &C::Func1<int>;
}
if you want something else could you show an example of using the pointer you want?