Без C ++ 11 вы не можете избежать указания типа возврата функции.
template<typename R, typename F>
R bar(F func) {
return func();
}
bar<int>(foo);
С новыми функциями C ++ 11 вы можете.
template<typename F>
auto baz(F func) -> decltype(func()) {
return func();
}
baz(foo);
Вы можете шаблонировать функцию / функтор как параметр, вместо того, чтобы пытаться указать, что это должен быть 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);
}
Это позволяет довольно просто передать указатель на функцию.
f(zero);
f(one, 1);
f(two, 1, 2);
Если вам действительно нужно использовать функции или привязку, вы можете передать их в тот же интерфейс.
// 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);
Как и с функтором, который типичен для передачи в строгом порядке слабого упорядочения стандартным контейнерам.
struct zoobies {
void operator()() const {}
};
f(zoobies());
Он не должен проверять тип того, что вы ему передаете, только то, что он удовлетворяет интерфейсу. Это одна из причин, по которой шаблоны C ++ обычно намного мощнее, чем шаблоны в других языках.
И для полноты ... Если вы действительно хотите ограничить его в boost :: function, вот пример.
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);
Обновление:
void foo() {cout << "zero" << endl;}
void foo(int a) {cout << "one" << endl;}
void foo(int a, int b) {cout << "two" << endl;}
boost :: bind работает из коробки, с этим, хотя у сырых указателей на функции есть большая проблема. Фу там неоднозначно.
f( (void(*)()) foo );
f( (void(*)(int)) foo, 1 );
f( (void(*)(int,int)) foo, 1, 2);
Если вы полностью укажете указатель на функцию, он сработает, хотя это не то, что кто-то хочет делать.
Используя в качестве доказательства boost :: bind, вы сможете определить арность по соглашению о вызовах f
. Если сегодня у меня будет время, я поиграю с ним.