How to create a signature of function templates?

I have such template functions:

template<class R> list<R> f(const boost::function<R()>&); template<class R, class A0> list<R> f(const boost::function<R(T0)>&, list<A0>); template<class R, class A0, class A1> list<R> f(const boost::function<R(T0)>&, list<A0>, list<A1>); 

To start one of them I need to write, for example:

 int one() { return 1; } int inc(int x) { return x + 1; } list<int> l; f<int>(one); f<int, int>(inc, l); 

And my goal is just to write:

 f(one); f(inc, l); 

I heard that this is possible thanks to some specialized specialization of templates, but I can’t figure out how to do this.

+4
source share
1 answer

Without C ++ 11, you cannot avoid specifying the type of function return.

 template<typename R, typename F> R bar(F func) { return func(); } bar<int>(foo); 

With the new features of C ++ 11 you can, however.

 template<typename F> auto baz(F func) -> decltype(func()) { return func(); } baz(foo); 

You can configure the function / functor as a parameter, instead of specifying that it should be a boost :: function.

 void zero() {cout << "zero" << endl;} void one(int a) {cout << "one" << endl;} void two(int a, int b) {cout << "two" << endl;} template<typename F> void f(const F &func) { func(); } template<typename F, typename T0> void f(const F &func, T0 t0) { func(t0); } template<typename F, typename T0, typename T1> void f(const F &func, T0 t0, T1 t1) { func(t0, t1); } 

This allows you to simply pass a pointer to a function.

 f(zero); f(one, 1); f(two, 1, 2); 

If you really need to use functions or bindings, you can pass this to the same interface.

 // without specifying the function f(boost::bind(zero)); f(boost::bind(one, _1), 1); f(boost::bind(two, _1, _2), 1, 2); // or by specifying the object boost::function<void()> f0 = boost::bind(zero); boost::function<void(int)> f1 = boost::bind(one, _1); boost::function<void(int,int)> f2 = boost::bind(two, _1, _2); f(f0); f(f1, 1); f(f2, 1, 2); 

As with the functor, which is typical for passing in a strict weak order in standard containers.

 struct zoobies { void operator()() const {} }; f(zoobies()); 

There is no need to check the type of what you pass to it, only that it satisfies the interface. This is one of the reasons why C ++ templates are generally much more powerful than generics in other languages.

And for completeness ... If you really wanted to limit it to boost ::, here is an example.

 template<typename T> void p(const boost::function<T> &func) { func(); } template<typename T, typename A0> void p(const boost::function<T> &func, A0 a0) { func(a0); } boost::function<void()> f0(zero); p(f0); boost::function<void(int)> f1(one, _1); p(f1, 1); 

Update:

 void foo() {cout << "zero" << endl;} void foo(int a) {cout << "one" << endl;} void foo(int a, int b) {cout << "two" << endl;} 

boost :: bind works out of the box, even though the original function pointers have a big problem. Here foo is ambiguous.

 f( (void(*)()) foo ); f( (void(*)(int)) foo, 1 ); f( (void(*)(int,int)) foo, 1, 2); 

If you completely point to a function pointer, this will work, although this is not what someone wants to do.

With boost :: bind as proof, you must define arity from the calling convention f . If I get some time today, I will play with him.

+2
source

Source: https://habr.com/ru/post/1393006/


All Articles