Overloaded function as argument of variadic template function - c++

I'm trying to make variadic template function, which takes as arguments overloaded function and its arguments :)
int sumall(int a) { return a; }
int sumall(int a, int b) { return a+b; }
template<typename R, typename... A>
R doit( R(*f)(A...), A... a) {
return f(a...); }
I want to call doit without any template specifiers nor casting:
cout << doit(sumall, 7, 6) << endl
That doesn't compile, but when return types are void, everything work perfect:
void printsum(int a) { cout << a << endl; }
void printsum(int a, int b) { cout << a+b << endl; }
template<typename... A>
void vdoit( void(*f)(A...), A... a) {
f(a...); }
// ...
vdoit(printsum, 7, 6);
Is it possible to modify first template to work with modyfing only doit template (I want to preserve sumall functions and doit call)? I think it can be done with removing typename R and leaving just template<typename... A> since R depends on A... and f, but I don't have any idea how to show that dependency.

When taking a pointer of a function the compiler needs to know which of the overloads you want to use. There is no way to pass a pointer to an "overload set" and have the compiler decide later. Neither of you examples works with any of the compilers I tried (very recent versions of EDG, gcc, and clang).
I don't think you can do what you want without changing the notation of your call. If you are willing to change the call you can encapsulate the knowledge about the function to be called into a class, e.g.:
struct sumall_t {
template <typename... T>
auto operator()(T... args) -> decltype(sumall(args...)) {
return sumall(args...);
}
};
This effectively creates a wrapper for an overload set. Since the result type can't be deduced directly and may depend on how the function is called, you'd need to use a different version of doit() as well:
template<typename Func, typename... A>
auto doit( Func f, A... a) ->decltype(f(a...)) {
return f(a...);
}
This would then be used something like this:
doit(sumall_t(), 1, 2);
Another way to fix this is to mandate specification of the result type: in some way you try to do two things at once: you want to deduce the result type of the function to be called and you want to guide the compiler to choose a specific overload of a result set. However, these are interdependent. If you remove any dependency on deducing any template from the function pointer, you don't need wrap the overload set because you can determine the choice of overloaded function from the first argument to the function. In case you claim that "my compiler can do it if the return type isn't void" I'd say that your compiler is actually wrong in doing this.

(If you're prepared to use variadic macros, then scroll to the end of this answer to see a better answer which make everything fully variadic. But I think that variadic macros are just a g++ extension.)
It can be made to work, if you're prepared to put the name of the function at the end of the parameter list. By putting it later, the compiler can deduce the necessary types from the earlier parameters to doit:
cout << doit(7, 6, sumall) << endl;
cout << doit(10, sumall) << endl;
Here is a demo on ideone.
The downside is that you have to implement one doit for each number of parameters. I've only implemented it for one- and two- parameter functions, but it shouldn't be a problem to extend this:
int sumall(int a) { return a; }
int sumall(int a, int b) { return a+b; }
template<typename A1, typename A2, typename R>
auto doit( A1 a1, A2 a2, R (*f) (A1,A2)) -> R {
return f(a1, a2);
}
template<typename A1, typename R>
auto doit( A1 a1, R (*f) (A1)) -> R {
return f(a1);
}
Update: Sometimes, it might appear that you can get away with having f as the first argument. But that's not as robust as putting it at the end. Consider the example where where are two functions that take the same number of arguments, but different types of parameters. e.g.:
int sumall(int a, int b) { return a+b; }
string sumall(string a, string b) { return a+" "+b; }
You need to have the function as the last argument, in order that the template deduction can use the type and number of parameters at the start to deduce the types of the arguments. Here's a demo on ideone of function-arg first and function-arg last.
The only downside with putting the arg at the end is that we can't then use variadic templates - variadic arg packs must be at the end. And you must get the types exactly right - see how I had to use string("hi") instead of simply "hi".
Using variadic macros to have the best of all worlds
By implementing doit as a macro, and using variadic macros (a gcc/g++ extension), it is possible to have a fully variadic solution with the function name appearing first. A demo on ideone.
cout << doit(sumall, 7, 6) << endl;
cout << doit(sumall, 10) << endl;
cout << doit(sumall, string("hi"), string("world")) << endl;
By using decltype and a couple of other simple classes, we can use the args provided to deduce the types of the args and then it can use that to select the right method from the overload set and deduce the return type from that.
template<typename ...Args>
struct OverloadResolved {
template<typename R>
static auto static_doit( R (*f) (Args...), Args ... args ) -> R {
return f(args...);
}
};
template<typename ...Args>
auto deduce(Args...) -> OverloadResolved<Args...> {
return OverloadResolved<Args...>();
}
template<typename T>
struct dummy : public T { };
#define doit(f, ...) ( dummy<decltype(deduce( __VA_ARGS__ ))> :: static_doit(f, __VA_ARGS__) )
I'm pretty sure this is a safe use of macros, nothing will be evaluated twice (nothing inside decltype actually executes.

Related

Is there a way to detect at compile time whether a generic lambda can be successfully invoked with a given set of parameter types?

I would like to be able to determine at compile time, given a generic lambda type, whether it can be invoked with a given set of parameter types. I have the following example C++14 implementation:
#include <iostream>
// helper function; this overload handles the case that the call is possible
// use SFINAE with the extra template parameter to remove this from consideration when the
// call is ill-formed
template <typename Func, typename... Args, typename = decltype(std::declval<Func>()(std::declval<Args>()...))>
auto eval(Func f, Args &&... args) { return f(args...); }
// special type returned from `eval()` when the call can't be done
struct invalid_call { };
// helper function; this overload handles the case that the call is not possible
template <typename Func>
invalid_call eval(Func f, ...) { return invalid_call{}; };
// bring in std::negation from C++17 to help create the below trait
template<class B>
struct negation : std::integral_constant<bool, !bool(B::value)> { };
// trait that determines whether `Func` can be invoked with an argument list of types `Args...`
template <typename Func, typename... Args>
using can_call = negation<std::is_same<decltype(eval(std::declval<Func>(), std::declval<Args>()...)), invalid_call>>;
// arbitary type that has no `operator+`
struct foo {};
int main()
{
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
using FuncType = decltype(func);
std::cout << "can call with (int, int): " << can_call<FuncType, int, int>::value << std::endl;
std::cout << "can call with (foo, foo): " << can_call<FuncType, foo, foo>::value << std::endl;
}
This example works fine as-is. What I don't like is the cumbersome way that the lambda must be declared:
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
That is, the trailing return type must be specified because C++14's deduced return types don't work with SFINAE. Return type deduction requires substitution of the argument list types into the callable's template call operator, and the program is ill-formed if an error occurs there.
Ideally, I would be able to do the following:
auto func = [](auto a1, auto a2) { return a1 + a2; };
and let the return type work itself out automatically; this would be the most intuitive interface to provide to my users. This is a very simple example, so the argument to the decltype() doesn't look bad, but in practice, the lambda might be several statements, which wouldn't work with this approach. So my question is:
Using any modern C++ techniques (C++14 would be best, but I'm open to newer features as well if needed), is there any way I can test at compile time whether a generic lambda can possibly be invoked with an arbitrary list of parameter types?
Sure, using the C++98 feature of macros
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { return __VA_ARGS__; }
then
auto func = [](auto a1, auto a2) RETURNS(a1+a2);
does it.
There is a C++20 proposal by our very own #Barry that makes this
auto func = [](auto a1, auto a2) => a1+a2;
without the use of macros.
In general, it is not possible, nor is it intended to be possible, to force the body of a function or lambda to be compiled to determine if a SFINAE expression is acceptable or not. Such errors are supposed to be hard, as this simplifies the work of C++ compilers; they don't have to be able to compile entire bodies of arbitrary functions and then cleanly backout to an errorless state while determining if overload resolution succeeds or not.
In the case of more than one return statement or a long set of complex types used in the return statement, you are out of luck. Write the decltype. Pray you get it right.

Containers for different signature functions

I'm trying to programming in C++ a framework where the user can indicates a set of functions inside its program where he wants to apply a memoization strategy.
So let's suppose that we have 5 functions in our program f1...f5 and we want to avoid the (expensive) re-computation for the functions f1 and f3 if we already called them with the same input. Notice that each function can have different return and argument types.
I found this solution for the problem, but you can use only double and int.
MY SOLUTION
Ok I wrote this solution for my problem, but I don't know if it's efficient, typesafe or can be written in any more elegant way.
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(function<ReturnType(Args...)> func)
{
return ([=](Args... args) mutable {
static map<tuple<Args...>, ReturnType> cache;
tuple<Args...> t(args...);
auto result = cache.insert(make_pair(t, ReturnType{}));
if (result.second) {
// insertion succeeded so the value wasn't cached already
result.first->second = func(args...);
}
return result.first->second;
});
}
struct MultiMemoizator
{
map<string, boost::any> multiCache;
template <typename ReturnType, typename... Args>
void addFunction(string name, function < ReturnType(Args...)> func) {
function < ReturnType(Args...)> cachedFunc = memoize(func);
boost::any anyCachedFunc = cachedFunc;
auto result = multiCache.insert(pair<string, boost::any>(name,anyCachedFunc));
if (!result.second)
cout << "ERROR: key " + name + " was already inserted" << endl;
}
template <typename ReturnType, typename... Args>
ReturnType callFunction(string name, Args... args) {
auto it = multiCache.find(name);
if (it == multiCache.end())
throw KeyNotFound(name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(args...);
}
};
And this is a possible main:
int main()
{
function<int(int)> intFun = [](int i) {return ++i; };
function<string(string)> stringFun = [](string s) {
return "Hello "+s;
};
MultiMemoizator mem;
mem.addFunction("intFun",intFun);
mem.addFunction("stringFun", stringFun);
try
{
cout << mem.callFunction<int, int>("intFun", 1)<<endl;//print 2
cout << mem.callFunction<string, string>("stringFun", " World!") << endl;//print Hello World!
cout << mem.callFunction<string, string>("TrumpIsADickHead", " World!") << endl;//KeyNotFound thrown
}
catch (boost::bad_any_cast e)
{
cout << "Bad function calling: "<<e.what()<<endl;
return 1;
}
catch (KeyNotFound e)
{
cout << e.what()<<endl;
return 1;
}
}
How about something like this:
template <typename result_t, typename... args_t>
class Memoizer
{
public:
typedef result_t (*function_t)(args_t...);
Memoizer(function_t func) : m_func(func) {}
result_t operator() (args_t... args)
{
auto args_tuple = make_tuple(args...);
auto it = m_results.find(args_tuple);
if (it != m_results.end())
return it->second;
result_t result = m_func(args...);
m_results.insert(make_pair(args_tuple, result));
return result;
}
protected:
function_t m_func;
map<tuple<args_t...>, result_t> m_results;
};
Usage is like this:
// could create make_memoizer like make_tuple to eliminate the template arguments
Memoizer<double, double> memo(fabs);
cout << memo(-123.456);
cout << memo(-123.456); // not recomputed
It's pretty hard to guess at how you're planning to use the functions, with or without memoisation, but for the container-of-various-function<>s aspect you just need a common base class:
#include <iostream>
#include <vector>
#include <functional>
struct Any_Function
{
virtual ~Any_Function() {}
};
template <typename Ret, typename... Args>
struct Function : Any_Function, std::function<Ret(Args...)>
{
template <typename T>
Function(T& f)
: std::function<Ret(Args...)>(f)
{ }
};
int main()
{
std::vector<Any_Function*> fun_vect;
auto* p = new Function<int, double, double, int> { [](double i, double j, int z) {
return int(i + j + z);
} };
fun_vect.push_back(p);
}
The problem with this is how to make it type-safe. Look at this code:
MultiMemoizator mm;
std::string name = "identity";
mm.addFunction(name, identity);
auto result = mm.callFunction(name, 1);
Is the last line correct? Does callFunction have the right number of parameters with the right types? And what is the return type?
The compiler has no way to know that: it has no way of understanding that name is "identity" and even if it did, no way to associate that with the type of the function. And this is not specific to C++, any statically-typed language is going to have the same problem.
One solution (which is basically the one given in Tony D's answer) is to tell the compiler the function signature when you call the function. And if you say it wrong, a runtime error occurs. That could look something like this (you only need to explicitly specify the return type, since the number and type of parameters is inferred):
auto result = mm.callFunction<int>(name, 1);
But this is inelegant and error-prone.
Depending on your exact requirements, what might work better is to use "smart" keys, instead of strings: the key has the function signature embedded in its type, so you don't have to worry about specifying it correctly. That could look something like:
Key<int(int)> identityKey;
mm.addFunction(identityKey, identity);
auto result = mm.callFunction(identityKey, 1);
This way, the types are checked at compile time (both for addFunction and callFunction), which should give you exactly what you want.
I haven't actually implemented this in C++, but I don't see any reason why it should be hard or impossible. Especially since doing something very similar in C# is simple.
you can use vector of functions with signature like void someFunction(void *r, ...) where r is a pointer to result and ... is variadic argument list. Warning: unpacking argument list is really inconvenient and looks more like a hack.
At first glance, how about defining a type that has template arguments that differ for each function, i.e.:
template <class RetType, class ArgType>
class AbstractFunction {
//etc.
}
have the AbstractFunction take a function pointer to the functions f1-f5 with template specializations different for each function. You can then have a generic run_memoized() function, either as a member function of AbstractFunction or a templated function that takes an AbstractFunction as an argument and maintains a memo as it runs it.
The hardest part will be if the functions f1-f5 have more than one argument, in which case you'll need to do some funky things with arglists as template parameters but I think C++14 has some features that might make this possible. An alternative is to rewrite f1-f5 so that they all take a single struct as an argument rather than multiple arguments.
EDIT: Having seen your problem 1, the problem you're running into is that you want to have a data structure whose values are memoized functions, each of which could have different arguments.
I, personally, would solve this just by making the data structure use void* to represent the individual memoized functions, and then in the callFunction() method use an unsafe type cast from void* to the templated MemoizedFunction type you need (you may need to allocate MemoizedFunctions with the "new" operator so that you can convert them to and from void*s.)
If the lack of type safety here irks you, good for you, in that case it may be a reasonable option just to make hand-written helper methods for each of f1-f5 and have callFunction() dispatch one of those functions based on the input string. This will let you use compile-time type checking.
EDIT #2: If you are going to use this approach, you need to change the API for callFunction() slightly so that callFunction has template args matching the return and argument types of the function, for example:
int result = callFunction<int, arglist(double, float)>("double_and_float_to_int", 3.5, 4);
and if the user of this API ever types the argument type or return types incorrectly when using callFunction... pray for their soul because things will explode in very ugly ways.
EDIT #3: You can to some extent do the type checking you need at runtime using std::type_info and storing the typeid() of the argument type and return type in your MemoizedFunction so that you can check whether the template arguments in callFunction() are correct before calling - so you can prevent the explosion above. But this will add a bit of overhead every time you call the function (you could wrap this in a IF_DEBUG_MODE macro to only add this overhead during testing and not in production.)

Deducing type for overloaded functions - currying

Given a callable object ( a function ) a, and an argument b ( or a series of arguments ), I would like to deduce the type returned from f considering that f is overloaded with multiple signatures.
one of my many attempts is
#include <iostream>
#include <cstdint>
#include <string>
#include <functional>
#include <utility>
#include <typeinfo>
int foo(uint32_t a) { return ((a + 0) * 2); }
bool foo(std::string a) { return (a.empty()); }
/*template <typename A, typename B> auto bar(A a, B b) -> decltype(a(b)) {
return (a(b));
}*/
/*template <typename A, typename B> decltype(std::declval<a(b)>()) bar(A a, B b)
{
return (a(b));
}*/
template <typename A, typename B> void bar(std::function<A(B)> a, B b) {
std::cout << a(b) << "\n";
}
int main() {
// the following 2 lines are trivial and they are working as expected
std::cout << foo(33) << "\n";
std::cout << typeid(decltype(foo(std::string("nothing")))).name() << "\n";
std::cout << bar(foo, 33) << "\n";
//std::cout << bar(foo, std::string("Heinz")) << "\n";
return (0);
}
and 2 templates options are commented out and included in the previous code.
I'm using declval result_of auto decltype without any luck.
How does the overloading resolution process works at compile time ?
If anyone wants to know why I'm trying to get creative with this, is that I'm trying to implement some Currying in C++11 in a workable/neat way.
The problem is that you can't easily create a function object from an overload set: when you state foo or &foo (the function decays into a function pointer in most case, I think) you don't get an object but you get an overload set. You can tell the compiler which overload you want by either calling it or providing its signature. As far as I can tell, you don't want either.
The only approach I'm aware of is to turn your function into an actual function object which makes the problem go away:
struct foo_object
{
template <typename... Args>
auto operator()(Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) {
return foo(std::forward<Args>(args)...);
}
};
With that wrapper which is unfortunately needed for each name, you can trivially deduce the return type, e.g.:
template <typename Func, typename... Args>
auto bar(Func func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
// do something interesting
return func(std::forward<Args>(args)...);
}
int main() {
bar(foo_object(), 17);
bar(foo_object(), "hello");
}
It doesn't quite solve the problem of dealing with overload sets but it gets reasonably close. I experimented with this idea, essentially also for the purpose of currying in the context of an improved system of standard library algorithms and I'm leaning towards the algorithms actually being function objects rather than functions (this is desirable for various other reasons, too; e.g., you don't need to faff about when you want to customize on algorithm with another one).
If foo is overloaded, you need to use the following:
#include <type_traits>
int foo(int);
float foo(float);
int main() {
static_assert(std::is_same<decltype(foo(std::declval<int>())), int>::value, "Nope.");
static_assert(std::is_same<decltype(foo(std::declval<float>())), float>::value, "Nope2.");
}
If it's not, then this will suffice:
#include <type_traits>
bool bar(int);
int main() {
static_assert(std::is_same<std::result_of<decltype(bar)&(int)>::type, bool>::value, "Nope3.");
}
Yes, it is verbose because you're trying to explicitly extract what implicit ad-hoc overloading does for you.
This is actually already implemented for you std::result_of. Here is a possible implementation
template<class>
struct result_of;
// C++11 implementation, does not satisfy C++14 requirements
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
typedef decltype(
std::declval<F>()(std::declval<ArgTypes>()...)
) type;
};

Boost bind placeholder argument equal to the number of Variadic Template arguments

I want to know if it is possible to use the number of arguments passed to a variadic template as placeholder in a boost::bind call.
Something like this:
template <typename ... Args>
boost::bind(&function, this, anArg, _1)); //If Args count equals 1
boost::bind(&function, this, anArg, _1, _2)); //If Args count equals 2
boost::bind(&function, this, anArg, _1, _2, _3)); //If Args count equals 3
Is this possible?
Thank you
There definitely is a way with partial specialization.
your variadic doesn't know the number of arguments right away right ? you have to use compile-time recursion, during this time you can stack your arguments using boost::mpl (or count them using a simple integral constant increment).
then in your last non-variadic recursion call (with 0 arg) you call mpl::size on your container (or just use the integral counter if you chose that way) to call a Callable like the other answer, that bears all the arguments, plus one integral template paramater at the beginning of the type list. and that is what you specialize. you make a caller for each number of arguments that will call the correct bind according to its specialized number of arguments.
(the Callable structures are (partially) specialized according to the number of argument integral template parameter. and even though the Call function takes the max number of argument, it only wraps the correct boost::bind call for example the bind(..,_1,_2) for the Callable<2, T1, T2, T3>)
its not terrible, but I confirm that I have used this approach in C++03 in the past.
Maybe you should explain what you want to do in a little bit more detail. If you're just looking for a solution to handle three different signatures which differ by their parameter types, you could do something like that:
template<typename signature>
struct callable;
template<typename P0, typename P1, typename P2>
struct callable<void (P0, P1, P2)>
{
void bind()
{
boost::bind(&callable::operator(), this, _1, _2, _3);
}
void operator()(P0, P1, P2) {}
};
This is not an answer to the specific problem, but a nice workaround for the problem you are likely trying to solve.
I ran into the same issue when implementing a generic delegate mechanism. My solution was to use a wrapper on top of just the bind call, specializing that for the variations. While it does not solve the issue, it definitely minimizes the redundant code to just the bind call and most importantly gives me a variadic parameter based delegate system I can use everywhere.
template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(), CALLBACK_TARGET_CLASS* callbackTarget)
{
return std::bind(memberFunction, callbackTarget);
}
template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0), CALLBACK_TARGET_CLASS* callbackTarget)
{
return std::bind(memberFunction, callbackTarget, std::placeholders::_1);
}
template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0, typename P1>
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0, P1), CALLBACK_TARGET_CLASS* callbackTarget)
{
return std::bind(memberFunction, callbackTarget, std::placeholders::_1, std::placeholders::_2);
}
template<typename RETURNTYPE, typename... ARGS>
struct Delegate
{
std::function<RETURN_TYPE (ARGS...)> callbackFunction;
template<class CALLBACK_TARGET_CLASS>
void Bind(CALLBACK_TARGET_CLASS* callbackTarget, RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(ARGS...))
{
callbackFunction = BindFunction<CALLBACK_TARGET_CLASS, RETURN_TYPE, ARGS...>(memberFunction, callbackTarget);
}
void Callback(ARGS... params)
{
callbackFunction(params...);
}
};
Usage ends us looking like this..
class Foo
{
public:
void Bar(int x);
}
Foo foo;
Delegate<void, int> myDelegate;
myDelegate.Bind(&foo, &Foo::Bar);
myDelegate.Callback(3);
Using _1, _2, ... directly is not possible with variadic template. You need to use expansive macros instead.
However, you can wrap theses placeholders in a templated factory to get _1 with the template argument 1, _2 for 2, etc ...
Implementations such as gcc / msvc already define placeholders as templated struct (respectively std::_Placeholder and std::_Ph) so you can define you factory this way:
struct ph_factory {
template<size_t holder>
static std::_Placeholder<holder> make_ph() {
return std::_Placeholder<holder>();
}
};
This defined, you can expand a parameter pack with all the placeholders you want :
struct tester {
template<size_t ... holders>
void test(int val) {
auto callable = std::bind(&tester::call, this, val, ph_factory::make_ph<holders>()...);
callable('a', 42, 'c');
}
void call(int v1, char c1, int v2, char c2) {
cout << "calling :" << v1 << " " << c1 << " " << v2 << " " << c2 << endl;
}
};
So the following code will output "calling:10 c 42 a"
int main() {
tester t;
t.test<3,2,1>(10);
}
Using tricks like make_indice will grant you the possibility to achieve you original goal.

Function passed as template argument

I'm looking for the rules involving passing C++ templates functions as arguments.
This is supported by C++ as shown by an example here:
void add1(int &v) { v += 1 }
void add2(int &v) { v += 2 }
template <void (*T)(int &)>
void doOperation()
{
int temp = 0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
Learning about this technique is difficult, however. Googling for "function as a template argument" doesn't lead to much. And the classic C++ Templates The Complete Guide surprisingly also doesn't discuss it (at least not from my search).
The questions I have are whether this is valid C++ (or just some widely supported extension).
Also, is there a way to allow a functor with the same signature to be used interchangeably with explicit functions during this kind of template invocation?
The following does not work in the above program, at least in Visual C++, because the syntax is obviously wrong. It'd be nice to be able to switch out a function for a functor and vice versa, similar to the way you can pass a function pointer or functor to the std::sort algorithm if you want to define a custom comparison operation.
struct add3 {
void operator() (int &v) {v += 3;}
};
...
doOperation<add3>();
Pointers to a web link or two, or a page in the C++ Templates book would be appreciated!
Yes, it is valid.
As for making it work with functors as well, the usual solution is something like this instead:
template <typename F>
void doOperation(F f)
{
int temp = 0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}
which can now be called as either:
doOperation(add2);
doOperation(add3());
See it live
The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)
Template parameters can be either parameterized by type (typename T) or by value (int X).
The "traditional" C++ way of templating a piece of code is to use a functor - that is, the code is in an object, and the object thus gives the code unique type.
When working with traditional functions, this technique doesn't work well, because a change in type doesn't indicate a specific function - rather it specifies only the signature of many possible functions. So:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op(4,5,add);
Isn't equivalent to the functor case. In this example, do_op is instantiated for all function pointers whose signature is int X (int, int). The compiler would have to be pretty aggressive to fully inline this case. (I wouldn't rule it out though, as compiler optimization has gotten pretty advanced.)
One way to tell that this code doesn't quite do what we want is:
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
is still legal, and clearly this is not getting inlined. To get full inlining, we need to template by value, so the function is fully available in the template.
typedef int(*binary_int_op)(int, int); // signature for all valid template params
template<binary_int_op op>
int do_op(int a, int b)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op<add>(4,5);
In this case, each instantiated version of do_op is instantiated with a specific function already available. Thus we expect the code for do_op to look a lot like "return a + b". (Lisp programmers, stop your smirking!)
We can also confirm that this is closer to what we want because this:
int (* func_ptr)(int,int) = add;
int c = do_op<func_ptr>(4,5);
will fail to compile. GCC says: "error: 'func_ptr' cannot appear in a constant-expression. In other words, I can't fully expand do_op because you haven't given me enough info at compiler time to know what our op is.
So if the second example is really fully inlining our op, and the first is not, what good is the template? What is it doing? The answer is: type coercion. This riff on the first example will work:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
float fadd(float a, float b) { return a+b; }
...
int c = do_op(4,5,fadd);
That example will work! (I am not suggesting it is good C++ but...) What has happened is do_op has been templated around the signatures of the various functions, and each separate instantiation will write different type coercion code. So the instantiated code for do_op with fadd looks something like:
convert a and b from int to float.
call the function ptr op with float a and float b.
convert the result back to int and return it.
By comparison, our by-value case requires an exact match on the function arguments.
Function pointers can be passed as template parameters, and this is part of standard C++
. However in the template they are declared and used as functions rather than pointer-to-function. At template instantiation one passes the address of the function rather than just the name.
For example:
int i;
void add1(int& i) { i += 1; }
template<void op(int&)>
void do_op_fn_ptr_tpl(int& i) { op(i); }
i = 0;
do_op_fn_ptr_tpl<&add1>(i);
If you want to pass a functor type as a template argument:
struct add2_t {
void operator()(int& i) { i += 2; }
};
template<typename op>
void do_op_fntr_tpl(int& i) {
op o;
o(i);
}
i = 0;
do_op_fntr_tpl<add2_t>(i);
Several answers pass a functor instance as an argument:
template<typename op>
void do_op_fntr_arg(int& i, op o) { o(i); }
i = 0;
add2_t add2;
// This has the advantage of looking identical whether
// you pass a functor or a free function:
do_op_fntr_arg(i, add1);
do_op_fntr_arg(i, add2);
The closest you can get to this uniform appearance with a template argument is to define do_op twice- once with a non-type parameter and once with a type parameter.
// non-type (function pointer) template parameter
template<void op(int&)>
void do_op(int& i) { op(i); }
// type (functor class) template parameter
template<typename op>
void do_op(int& i) {
op o;
o(i);
}
i = 0;
do_op<&add1>(i); // still need address-of operator in the function pointer case.
do_op<add2_t>(i);
Honestly, I really expected this not to compile, but it worked for me with gcc-4.8 and Visual Studio 2013.
In your template
template <void (*T)(int &)>
void doOperation()
The parameter T is a non-type template parameter. This means that the behaviour of the template function changes with the value of the parameter (which must be fixed at compile time, which function pointer constants are).
If you want somthing that works with both function objects and function parameters you need a typed template. When you do this, though, you also need to provide an object instance (either function object instance or a function pointer) to the function at run time.
template <class T>
void doOperation(T t)
{
int temp=0;
t(temp);
std::cout << "Result is " << temp << std::endl;
}
There are some minor performance considerations. This new version may be less efficient with function pointer arguments as the particular function pointer is only derefenced and called at run time whereas your function pointer template can be optimized (possibly the function call inlined) based on the particular function pointer used. Function objects can often be very efficiently expanded with the typed template, though as the particular operator() is completely determined by the type of the function object.
The reason your functor example does not work is that you need an instance to invoke the operator().
Came here with the additional requirement, that also parameter/return types should vary.
Following Ben Supnik this would be for some type T
typedef T(*binary_T_op)(T, T);
instead of
typedef int(*binary_int_op)(int, int);
The solution here is to put the function type definition and the function template into a surrounding struct template.
template <typename T> struct BinOp
{
typedef T(*binary_T_op )(T, T); // signature for all valid template params
template<binary_T_op op>
T do_op(T a, T b)
{
return op(a,b);
}
};
double mulDouble(double a, double b)
{
return a * b;
}
BinOp<double> doubleBinOp;
double res = doubleBinOp.do_op<&mulDouble>(4, 5);
Alternatively BinOp could be a class with static method template do_op(...), then called as
double res = BinOp<double>::do_op<&mulDouble>(4, 5);
EDIT
Inspired by comment from 0x2207, here is a functor taking any function with two parameters and convertible values.
struct BinOp
{
template <typename R, typename S, typename T, typename U, typename V> R operator()(R (*binaryOp )(S, T), U u, V v)
{
return binaryOp(u,v);
}
};
double subD(double a, int b)
{
return a-b;
}
int subI(double a, int b)
{
return (int)(a-b);
}
int main()
{
double resD = BinOp()(&subD, 4.03, 3);
int resI = BinOp()(&subI, 4.03, 3);
std::cout << resD << std::endl;
std::cout << resI << std::endl;
return 0;
}
correctly evaluates to double 1.03 and int 1
Edit: Passing the operator as a reference doesnt work. For simplicity, understand it as a function pointer. You just send the pointer, not a reference.
I think you are trying to write something like this.
struct Square
{
double operator()(double number) { return number * number; }
};
template <class Function>
double integrate(Function f, double a, double b, unsigned int intervals)
{
double delta = (b - a) / intervals, sum = 0.0;
while(a < b)
{
sum += f(a) * delta;
a += delta;
}
return sum;
}
.
.
std::cout << "interval : " << i << tab << tab << "intgeration = "
<< integrate(Square(), 0.0, 1.0, 10) << std::endl;