#include <iostream>
class A { };
class B { };
class Executor {
public:
// Callback base class including placeholders for operators that
// are not overridden.
class Callback {
public:
virtual ~Callback() { }
virtual void operator()(A const &) {
std::cout << "Placeholder A" << std::endl;
}
virtual void operator()(B const &) {
std::cout << "Placeholder B" << std::endl;
}
};
// Template method that can take a Callback directly, or it can
// take a lambda and will wrap it as a Callback.
template <typename T_Callback>
void execute(T_Callback &&callback);
private:
// This method finds As and Bs to call the callback with.
// It is not a template method and can be located in a source
// (rather than header) file.
void run(Callback &callback) {
A a;
B b;
callback(a);
callback(b);
}
// Callback class for wrapping a lambda taking A.
template <typename T_Callback>
class CallbackFunctionA : public Callback {
public:
CallbackFunctionA(T_Callback &callback)
: callback_(callback) { }
// Define operator taking A.
virtual void operator()(A const &a) {
callback_(a);
}
// Use other placeholder operators.
using Callback::operator();
private:
T_Callback &callback_;
};
// Callback class for wrapping a lambda taking B.
template <typename T_Callback>
class CallbackFunctionB : public Callback {
public:
CallbackFunctionB(T_Callback &callback)
: callback_(callback) { }
// Define operator taking B.
virtual void operator()(B const &b) {
callback_(b);
}
// Use other placeholder operators.
using Callback::operator();
private:
T_Callback &callback_;
};
// Determine type in which to wrap T_Callback.
template <typename T_Callback>
class CallbackType {
private:
template <typename T>
static CallbackFunctionA<T> testlambda(void (T::*op)(A const &) const);
template <typename T>
static CallbackFunctionB<T> testlambda(void (T::*op)(B const &) const);
template <typename T>
static decltype(testlambda<T>(&T::operator())) testany(int);
template <typename T>
static T &testany(...);
public:
typedef decltype(testany<T_Callback>(0)) type;
};
};
template <typename T_Callback>
void Executor::execute(T_Callback &&callback) {
// Determine callback class to use and instantiate it.
typename CallbackType<T_Callback>::type cb = callback;
run(cb);
}
int main() {
Executor executor;
// Execute executor given a functor taking either A or B.
struct : Executor::Callback {
virtual void operator()(A const &) {
std::cout << "Functor A" << std::endl;
}
virtual void operator()(B const &) {
std::cout << "Functor B" << std::endl;
}
} callback;
executor.execute(callback);
// Execute executor given a lambda taking an A.
executor.execute(
[](A const &) {
std::cout << "Lambda A" << std::endl;
}
);
// Execute executor given a lambda taking a B.
executor.execute(
[](B const &) {
std::cout << "Lambda B" << std::endl;
}
);
}