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().
Related
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).
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);
}
I want to write a class method that takes a template parameter pack, but zero arguments, and "iterate" over the types:
struct Bar {
template <typename T, typename... Ts>
void foo() {
// something with T that involves Bar's members
foo<Ts...>();
}
};
What is the preferred way to implement this?
You may use the following:
struct Bar {
template <typename... Ts>
void foo() {
int dummy[] = {0 /*Manage case where Ts is empty*/,
(bar<Ts>(), void() /* To avoid overload `operator,` */, 0)...};
(void) dummy; // suppress warning for unused variable.
}
template <typename T>
void bar()
{
// something with T that involves Bar's members
}
};
In C++17, it can be simplified with Folding expression:
struct Bar {
template <typename... Ts>
void foo() {
(static_cast<void>(bar<Ts>()), ...);
}
template <typename T>
void bar()
{
// something with T that involves Bar's members
}
};
template<class...Fs>
void do_in_order(Fs&&...fs) {
int _[]={0, ( std::forward<Fs>(fs)(), void(), 0 )...};
(void)_;
}
hides the syntax required to execute a pack of function objects in left to right order.
Then:
struct Bar {
template <class... Ts>
void foo() {
do_in_order([&]{
using T = Ts;
// code
}...);
}
};
and in a conforming compiler, we will run the // code with T being each type from left to right.
Note that some compilers claiming to be C++11 compilers may fail to compile the above.
The advantage of this technique is that it hides the nasty "expand and evaluate templates" code within a function with a clear name. You write do_in_order once, and it usually suffices for almost every use of that array-expansion trick.
There are a two important reasons to use this kind of esoteric syntax instead of the "more simple" recursive solutions.
First, it makes things easier for the optimizer. Optimizers sometimes give up after a pile of recursive calls.
Second, the sum of the lengths names of the function signatures for the traditional recursive functions grow at O(n^2). If you use helper types, the total length of the names is also O(n^2). Unless you are careful, this can cause compile time, link time, and binary size bloat.
In C++1z there are plans for some "fold" syntax that may make the esoteric parts of the above less esoteric.
I like overloaded functions and using a typelist:
#include <iostream>
#include <typeinfo>
template <typename ...Ts> struct typelist { };
void foo_impl(typelist<> )
{
// we are finished
}
template <typename T, typename ...Ts>
void foo_impl(typelist<T, Ts...> )
{
std::cout << typeid(T).name() << ", ";
foo_impl(typelist<Ts...>{});
}
template <typename ...Ts>
void foo()
{
std::cout << "called with <";
foo_impl(typelist<Ts...>{});
std::cout << ">" << std::endl;
}
int main()
{
foo<int, char, float>();
}
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.
I'm writing a generalized function wrapper, that can wrap any function into a lua-style call, which has the form
int lua_function( lua_State *L)
And I wish the wrapper function is generated on-the-fly, so I'm thinking of passing the function as a template argument. This is trivial if you know the number (e.g, 2) of arguments:
template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper
However, I don't know the number, so I beg for variadic template argument for help
// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper
The above won't compile, since variadic argument has to be the last one. So I use two level template, the outer template captures types, the inner template captures the function:
template <typename R, typename... Args>
struct func_type<R(Args...)>
{
// Inner function wrapper take the function pointer as a template argument
template <R F(Args...)>
struct func
{
static int call( lua_State *L )
{
// extract arguments from L
F(/*arguments*/);
return 1;
}
};
};
That works, except that to wrap a function like
double sin(double d) {}
the user has to write
func_type<decltype(sin)>::func<sin>::apply
which is tedious.
The question is: is there any better, user-friendlier way to do it? (I can't use a function template to wrap the whole thing, coz a function parameter can't be used as a template argument.)
Things like std::function and std::result_of use the following technique to do what you want regarding variadic templates:
template<typename Signature>
struct wrapper; // no base template
template<typename Ret, typename... Args>
struct wrapper<Ret(Args...)> {
// instantiated for any function type
};
You could expand the above to add a non-type Ret(&P)(Args...) template parameter (pointers to function work just as well) but you'd still need a decltype at the user level, i.e. wrapper<decltype(sin), sin>::apply. Arguably it would be a legitimate use of the preprocessor if you decide to use a macro to remove the repetition.
template<typename Sig, Sig& S>
struct wrapper;
template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
int
static apply(lua_State*)
{
// pop arguments
// Ret result = P(args...);
// push result & return
return 1;
}
};
// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.
The above compiles with gcc-4.5 at ideone.
Good luck with implementing the apply that (variadically) pops the arguments (leave me a comment if you open a question about that). Have you considered using Luabind?
As #Juraj says in his comment, the function pointer can be a template argument, see the following simple example:
#include <iostream>
#include <boost/typeof/typeof.hpp>
void f(int b, double c, std::string const& g)
{
std::cout << "f(): " << g << std::endl;
}
template <typename F, F* addr>
struct wrapper
{
void operator()()
{
std::string bar("bar");
(*addr)(1, 10., bar);
}
};
int main(void)
{
wrapper<BOOST_TYPEOF(f), &f> w;
w();
return 0;
}
working version: http://www.ideone.com/LP0TO
I'm using BOOST_TYPEOF as normally I always provide examples in the current standard, but it does something similar to decltype. Is this what you were after?