Reputation: 6029
#include <iostream>
void padd(int a, int b) { std::cout << a + b << std::endl; }
void psub(int a, int b) { std::cout << a - b << std::endl; }
template <??? op>
class Foo {
public:
template<typename... Arguments>
void execute(Arguments... args) {
op(args ...);
}
};
int main() {
auto f1 = Foo<padd>();
f1.execute(5, 6); // ideally would print 11
auto f2 = Foo<psub>();
f2.execute(5, 6); // ideally would print -1
return 0;
}
I am trying to figure out how to bind functions (and, if possible, template functions) as template parameters in C++.
As it stands I am not aware if this is possible.
A kicker here is that the function signatures are not guaranteed to be similar.
edit: thanks to @sehe and @Potatoswatter, my current solution is thus: http://ideone.com/0jcbUi. Will write up answer when appropriate.
Upvotes: 7
Views: 246
Reputation: 6029
Thanks to Potatoswatter and sehe's help in the C++ Lounge and here, I have formulated the solution to my question.
#include <iostream>
#include <functional>
template <typename func_t, func_t func>
struct Foo {
template <typename... Arguments>
void execute(Arguments... args) {
func(args ...);
}
};
template <typename T, typename func_t, func_t func>
struct FooMember {
T member;
FooMember(T member) : member(member) {}
template <typename... Arguments>
void execute(Arguments... args) {
std::function<void(T&, Arguments ...)> f(func);
f(this->member, args ...);
}
};
struct Bar {
int z;
Bar(int z) : z(z) {}
void add(int x, int y) { std::cout << x + y + z << std::endl; }
};
void padd(int x, int y, int z) { std::cout << x + y + z << std::endl; }
int main() {
auto a = Foo<decltype(&padd), &padd>();
auto b = FooMember<Bar, decltype(&Bar::add), &Bar::add>(Bar(2));
a.execute(4, 5, 6); // prints 4+5+6 : 15
b.execute(4, 5); // prints 4+5+a.z : 4+5+2 : 11
return 0;
}
Upvotes: 0
Reputation: 137910
Just making the observation that you don't have or want runtime state. Partly an inference from your comments in the C++ chatroom.
Functions do not have unique types. If you want go generate a unique type that captures which function should be called, use a class template to do so.
template< typename t, t v >
struct constant {
typedef t type;
static constexpr t value = v;
operator t () { return v; }
};
This is essentially the same as std::integral_constant
but removes integral
from the name to save confusion. (Actually I only tested this using std::integral_constant
, if you want to be cleaner it's up to you.)
Now you can give the functions separate types which are stateless, default-constructible functors.
typedef constant< decltype( & padd ), padd > padd_type;
typedef constant< decltype( & psub ), psub > psub_type;
padd_type()( 2, 3 ); // prints 5
Note that stateless lambdas are convertible to function pointers and are compatible with such a system, but you need to specify the function pointer type explicitly. decltype
alone won't get you there.
Upvotes: 3
Reputation: 393694
I'd suggest letting the compiler worry about resolving function signatures when appropriate. http://ideone.com/ZeLt1E (code included below).
If you need to adapt overload sets or polymorphic interfaces, I would suggest also looking at BOOST_PHOENIX_ADAPT_FUNCTION.
Edit In response to the comments: Here's a demo of how you could use strictly function-pointers and/or pointer-to-member functions directly as function arguments. This is the other extreme approach: http://ideone.com/120Ezs
#include <iostream>
template <typename F>
struct Foo {
Foo(F&& f) : f(std::forward<F>(f)) {}
template<typename... Arguments>
void execute(Arguments... args) {
f(args ...);
}
private:
F f;
};
template <typename F>
Foo<F> make_foo(F&& f = F()) { return {f}; }
void padd(int a, int b) { std::cout << a + b << std::endl; }
void psub(int a, int b) { std::cout << a - b << std::endl; }
int main() {
auto f = make_foo(padd);
f.execute(5, 6);
make_foo(psub).execute(5, 6);
return 0;
}
Upvotes: 6