actual function as template parameter? - c++

Consider this hypothetical code snippet :
template<?? function>
void loop() {
for(int i =0; i < 10000; ++i ) {
function(i)
}
}
//...
void print(int i) {
std::cout << i << '\n';
}
//...
loop<print>();
is it possible to do something like that in C++ ? So far I know that function pointers and generic functors can be passed through templates parameters (like in std::sort), but is there a way to make it so that no actual object is passed during runtime and the call to "print" is completely direct (ie no indirection) ? ie transferring the actual function by "value" in the template, like it's possible to pass integer in a template using template <int i> or some other integral types.

Of course, it is possible. Template non-type parameters can be of function pointer type. In the most simplistic case, specifically tailored to your simple example it might look as follows
template <void (*function)(int)>
void loop() {
for(int i = 0; i < 10000; ++i ) {
function(i);
}
}
Note that C++03 stated that a valid template argument for such template must be a pointer to a function with external linkage. C++11 removed the external linkage requirement.

A simpler function template, without any bells and whistles :)
#include <iostream>
template<typename Function>
void loop(Function function) {
for(int i =0; i < 10000; ++i ) {
function(i);
}
}
void print(int i) {
std::cout << i << '\n';
}
int main()
{
loop(print);
return 0;
}

As has been noted in other answers, there is such a thing as function template parameters. However, sometimes it is desirable for the template parameter to be a type. This is especially useful with other kinds of template metaprogramming, e.g. to make a list of functions.
The following code allows you to wrap functions in types. There are different variants of the WRAP_FUNC macro for wrapping a function. The suffix-less one is for use outside of templates, the _T variant is for use within templates, and the _TI variant is for inheriting within templates (see below).
Note that in order to work with references, std::forward is used. Also, it must be used as written, with another parameter pack, CallArgs, for the types of arguments which call() is called with, as opposed to Args, which are the argument types for the given function.
#include <utility>
#include <stdio.h>
// This goes into a header.
template <typename R, typename... Args>
struct Helper {
template <R (*Func) (Args...)>
struct Wrapper {
template <typename... CallArgs>
static R call (CallArgs && ... args)
{
return Func(std::forward<CallArgs>(args)...);
}
};
};
template <typename R, typename... Args>
struct Helper<R, Args...> MakeHelper (R (*func) (Args...));
#define WRAP_FUNC(func) decltype(MakeHelper(func))::Wrapper<func>
#define WRAP_FUNC_T(func) typename decltype(MakeHelper(func))::template Wrapper<func>
#define WRAP_FUNC_TI(func) decltype(MakeHelper(func))::template Wrapper<func>
// Let's try it out.
static double test_func (int x, double y)
{
return x + y;
}
using TestFunc = WRAP_FUNC(test_func);
template <typename Func>
static void CallFunc ()
{
double r = Func::call(4, 6.0);
printf("%f\n", r);
}
int main ()
{
CallFunc<TestFunc>();
}
If the function can only be defined after being passed to the class that needs it (because it itself calls to the class that calls it and we don't want to separate its definition and declaration), inheritance can be used to work around the circular dependency. Here, the _TI form of the macro needs to be used if this is within a template.
template <.....>
class Qux {
struct CallbackFunc;
using MyFoo = Foo<CallbackFunc>;
static void callback_func ()
{
// Foo calls us but we call Foo!
MyFoo::bar();
}
struct CallbackFunc : public WRAP_FUNC_TI(callback_func) {};
};

Since you can pass pointers to templates as non-type parameters, you can pass function pointers to them as well. You may also consider one to pass function objects.
#include <iostream>
template <void (*f)()>
void loop() {
f();
}
template <typename F>
void loop() {
F()();
}
void F() {
std::cout << "F" << std::endl;
}
struct G {
void operator()() const {
std::cout << "G" << std::endl;
}
};
int main() {
loop<F>();
loop<G>();
}
Prints
F
G

There is no way to use a function rather than a function pointer as a template argument. There fairly few entities which can be used a template arguments. The non-type template parameters are listed in 14.1 [temp.param] paragraph 4:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
integral or enumeration type,
pointer to object or pointer to function,
lvalue reference to object or lvalue reference to function,
pointer to member,
std::nullptr_t.

Related

Pass templated function as a std::function and choose template argument later

I am trying to construct a function tune that takes a templated function via std::function and initializes a series of that function based on a std::integer_sequence. I am not sure whether this is possible, and I am stuck. I made a working example that shows what I aim to achieve: a generic function that takes another function and an integer list as an argument. I would like to be able to use the syntax that is in the two lines commented out in the bottom, because with the working code, I have to make a tune function for each function.
#include <iostream>
#include <functional>
template<int I> void print_value() { std::cout << I << std::endl; }
template<int I> void print_value_squared() { std::cout << I*I << std::endl; }
template<int... Is>
void tune_print_value(std::integer_sequence<int, Is...>)
{
(print_value<Is>(), ...);
}
/* NOT SURE HOW TO DO THIS...
template<class Func&&, int... Is>
void tune(std::function<Func> f, std::integer_sequence<int, Is...)
{
(f<Is>(), ...);
}
*/
int main()
{
std::integer_sequence<int, 1, 2, 3> is;
tune_print_value(is);
// I would like:
// tune(print_value, is);
// tune(print_value_squared, is);
return 0;
}
This is not possible with a simple function pointer or std::function (as it can only point to one instance of a particular template!) but what you can do though is to wrap each function print_value or print_value_squared in a corresponding struct
struct print_value {
template <int I>
static constexpr int impl() {
std::cout << I << std::endl;
return I;
}
};
This struct then holds the templated implementation as a static member function with a predefined name such as impl (sadly you can't use operator () like for a functor as it is not allowed to be static)
Your tune function then takes this struct as a template argument and "magically" (in C++20 you could create a concept for this as follows, prior to it you might use SFINAE and std::enable_if as follows) accesses the wrapped template function impl.
template<class Func, int... Is>
auto tune(std::integer_sequence<int, Is...>) {
return (Func::template impl<Is>(), ...);
}
You will need the keyword template as a qualifier in this case to tell the compiler that the member function is a template.
You can then call the tunefunction like
tune<print_value>(is);
Try it here with a static member function impl or here with a non-static operator().

Member function template to call a funcion on a data member with arbitrary arguments

I'm working on a C++11 code base and wondering how I can call any function on a member type passing arbitrary arguments. Note that since I'm using C++11 I can't use something like std::invoke.
I started creating a function template in the Outer class, but my initial try gives me a compile error.
#include <iostream>
#include <utility>
#include <type_traits>
struct Inner {
void bar(int x) {
std::cout << "Called: x=" << x << std::endl;
}
};
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Func, typename ... Args>
void CallInner(Func&& f, Args&& ... args) {
b->f(std::forward<Args>(args)...);
}
};
int main() {
Inner inner{};
Outer outer(&inner);
outer.CallInner(&Inner::bar, 5);
}
Try it out yourself
Again, I would like to keep the signature of the function CallInner unchanged from the above sample code.
Since f is a pointer a member function it needs to be dereferenced first before being called:
(b->*f)(std::forward<Args>(args)...);
You don't have much choice with regards to changing the signature, because at least one additional template is required.
The correct syntax is a little bit more complicated:
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Ret, typename ...FuncArgs, typename ... Args>
void CallInner(Ret (Inner::*f)(FuncArgs...), Args&& ... args) {
(b->*f)(std::forward<Args>(args)...);
}
};
The first parameter to CallInner must be a method pointer, and, in a template context, it needs to be templated not just by a set of variadic template parameters, FuncArgs, but also its return type, Ret. Then you also need a second set of variadic template parameters for the forwarding references of the arguments you're forwarding (which may not necessarily be the same as FuncArgs, hence the need for a separate set of variadic template types).

instantiating a template class which takes function pointers in constructor with different function signatures

I have a template class which takes a function pointer in constructor. A method in the class will later call that function depending on a condition. Can I have 2 objects of that class, each instantiated with function pointers with different signatures? Simplified code is given below.
#include <iostream>
using namespace std;
template <class FUNC>
class Thread {
public:
Thread(FUNC f1, int i)
: f(f1), val(i) {};
void run() {
if (val == 1)
f();
else
f(val); // here
}
private:
FUNC f;
int val;
};
void print() {
cout << "print" << endl;
}
void incr(int a) {
cout << "incremented value is " << ++a << endl;
}
int main () {
Thread<void(*)()> t1(print,1);
t1.run();
Thread<void(*)(int)> t2(incr,2);
t2.run();
}
run() decides which function to call based on val. Both probable functions have different signatures. I'm getting the following compilation errors when doing this.
testa.cpp: In member function 'void Thread<FUNC>::run() [with FUNC = void (*)()]':
testa.cpp:33: instantiated from here
testa.cpp:16: error: too many arguments to function
testa.cpp: In member function 'void Thread<FUNC>::run() [with FUNC = void (*)(int)]':
testa.cpp:35: instantiated from here
testa.cpp:14: error: too few arguments to function
How do I do this? And is there a way in c++ using templates to do this in the first place?
I think that the fact that your Thread class forces the client to provide an int argument whether or not the function pointer accepts arguments at all points to a bit of a design flaw. What you want is for the client to only pass the arguments they need.
One way to accomplish this with templates is to use template specialization to capture which arguments are necessary, like so:
template<class...>
class Thread;
template <class RET, class... ARGS>
class Thread<RET(*)(ARGS...)> {/*..*/}
From there, the rest of the specialization almost writes itself. If you can handle the overhead, I recommend using a std::function instantiated with a lambda so that you can bind the arguments received in Thread's constructor. This is nice because it makes the held type in Thread consistent. Then you don't have to try some kind of run-time switching between two versions of f()
template <class RET, class... ARGS>
class Thread<RET(*)(ARGS...)> {
public:
using fptr_t = RET(*)(ARGS...);
Thread(fptr_t fptr, ARGS... args)
{
f = [fptr, args...]{fptr(args...);};
}
void run() {
f();
}
private:
std::function<void(void)> f;
};
Demo
Of course this code should become more complicated for a production environment, considering copying/moving of both Thread objects, but also move semantics for arguments to bind to the function pointer.
In C++98* the best approach is likely template class specialization for void functions (zero argument), and separately for unary (single argument) functions:
template<class FN>
class Thread;
// void functions
template <class RET>
class Thread<RET(*)(void)> {/*..*/}
// unary functions
template <class RET, class ARG>
class Thread<RET(*)(ARG)> {/*..*/}
The benefit to this approach is that you're not placing extra variables into a class that doesn't need them (the void function class). Also, due to the way our specialization is written, we can change the return type of run to be the same as the return type for the function pointer:
template <class RET>
class Thread<RET(*)(void)> {
public:
typedef RET(*fptr_t)(void);
Thread(fptr_t fptr) : f(fptr) {}
RET run() {
return f();
}
private:
fptr_t f;
};
template <class RET, class ARG>
class Thread<RET(*)(ARG)> {
public:
typedef RET(*fptr_t)(ARG);
Thread(fptr_t fptr, ARG arg) : f(fptr), val(arg) {}
RET run() {
return f(val);
}
private:
fptr_t f;
ARG val;
};
And some tests:
Thread<void(*)()> t1(&print);
t1.run();
Thread<void(*)(int)> t2(&incr,2);
t2.run();
Thread<int(*)(int)> t3(&get_val, 42);
int return_value = t3.run();
std::cout << "t3 returned " << return_value << std::endl;
Output:
print
incremented value is 3
Returning 42
t3 returned 42
Demo
*which we've now learned you're using. And we're all very sorry for your luck

C++ Understanding the exact semantics of templates, esp. with functional parameters

I'm comfortable using templates when they simply parameterize over a type. However, I'm now beginning to use them in more complex applications (specifically, parameterizing over a function, as in C++ Template: typename and function to map to int ), and have been reduced essentially to trial and error (note in the above referenced question I can't get my code to compile).
What are the exact semantics of the template keyword (or the typename keyword when used outside the definition of a template), especially when you want a function as a parameter?
How do I define a template that takes a function as a parameter?
Once defined, how do I instantiate and use that template?
I'll accept the first complete answer that includes both a compilable example as well as clear, full explanation, of what's going on behind the magic?
CLARIFICATION: I understand how to use typename. My question is: What are the exact semantics of template definition, especially when applied to invocable parameters? and How do you define and instantiate a class which takes a function (or functor or something invokable) as a template parameter?
What are the exact semantics of the template and typename keywords, especially when you want a function as a parameter?
template introduces a template declaration (and also declarations of explicit instantiations and specialisations, but that's beyond the scope of this question). It's followed by the list of template parameters, in angle brackets <>.
Within that list, typename or class introduces a type parameter; one of three kinds of parameter, the others being non-type (value) parameters, and template parameters.
How do I define a template that takes a function as a parameter?
The simplest way is with a type parameter, which can be any type that can be called like a function; for example
template <typename F, typename... Args>
void call(F && f, Args &&... args) {f(std::forward<Args>(args)...);}
Once defined, how do I instantiate and use that template?
If it's a function template, simply call the function with appropriately typed arguments. The template parameters will be deduced from them:
void f1(int a, double b); // function
struct fn {
void operator()(std::string);
};
call(f1, 42, 1.5);
call(fn{}, "Hello");
call([](std::string s){std::cout << s}, "Lambda\n");
For class templates, you'd have to specify the function type, which can be a bit messy:
template <typename F>
struct thing {
F f;
};
thing<void(*)(int,double)> thing1 {f1};
thing<fn> thing2 {fn{}};
// Lambdas are problematic since the type has no name
//thing<???> thing3 {[]{std::cout << "Lambda\n";}};
The messiness could be avoided by using a factory function template to deduce the function type and instantiate the class template:
template <typename F>
thing<F> make_thing(F && f) {
return thing<F>(std::forward<F>(f));
}
auto thing1 = make_thing(f1);
auto thing2 = make_thing(fn{});
auto thing3 = make_thing([]{std::cout << "Lambda\n";});
Below some example (commented) code to show how functions can be used in a template. You can replace typename Parameter with typename... Parameter and p to p... if you want the first template to work for any number of fucntion arguments, which uses variadic templates.
#include <functional> // for std::function
#include <iostream>
// example functions
void func(int i)
{
std::cout << "Integer: " << i << ".\n";
}
int gunc(int i)
{
int result = i+1;
std::cout << "+Integer:" << result << ".\n";
return result;
}
// general non-restrictive template
template<typename Function, typename Parameter>
void call_twice(Function f, Parameter p)
{
f(p);
f(p);
}
// Restrict signature to void(int), but the return value can be anything: it will be ignored
void call_thrice(std::function<void(int)> f, int p)
{
f(p);
f(p);
f(p);
}
// Restrict signature to int(int), to exclude func
void call_four_times(std::function<int(int)> f, int p)
{
f(p);
f(p);
f(p);
f(p);
}
int main()
{
call_twice(func, 1); // instantiates void call_twice(void (*)(int), int)
call_twice(gunc, 1); // instantiated void call_twice(int (*)(int), int)
// Note I do not write the explicit types of func and gunc in the above comments, they're not important!
call_thrice(func, 10); // converts func to a std::function<void(int)>
call_thrice(gunc, 10); // return value can be ignored, so int(int) is convertible to void(int)
//call_four_times(func, 100); // will fail to compile: cannot convert a function of signature void(int) to one with signature int(int)
call_four_times(gunc, 100); // converts gunc to std::function<int(int)>
}
Live demo here.
The basic form of a template declaration starts anything of the form
template<typename T>
template<class T> // same as above
template<int N> // explicitly typed template parameter, need not be an int
template<typename... variadic_template_args>
And of course the forms with combinations of the above, including nested template types and all. Just remember the variadic template parameter must come last.
Templates are what the name implies: a blueprint to create a class with certain functionality expressed within the template definition.
Instantiation occurs when you actually call a template function (from either another instantiated template function or a non-template function), or for class templates, when you declare an object of the type, e.g. for std::vector:
std::vector<double> v; // instantiate the class template std::vector for type double
This is no different to templates that take functions as arguments. Note that functions decay to function pointers when passed to another function.
For example, a class template with a function as template parameter:
#include <iostream>
#include <type_traits> // for std::result_of
template<typename Function, Function f>
struct A
{
using function_type = Function;
template<typename... ArgTypes>
typename std::result_of<Function(ArgTypes...)>::type call(ArgTypes... args)
{
return f(args...);
}
};
void func(int i) { std::cout << "Integer: " << i << ".\n"; }
int main()
{
A<decltype(&func), func> a;
a.call(42);
}
Live demo here. Note the extra & in the decltype, because a function only decays to a function pointer when it is passed to a function, not when it is used as a template parameter. Note the "extra" typename before the std::result_of: this is required because its type typedef is a dependent name. These and other times you need to use the template and typename keywords, those are covered in Where and why do I have to put the “template” and “typename” keywords?
It's easier to use lambdas
template <typename F>
void herp(F function)
{
function("Hello from herp");
}
int main()
{
const auto deDerp = [] (const std::string& msg)
{
std::cout << msg << "\n";
};
herp(deDerp);
}

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);