Function Composition in C++ - c++

There are a lot of impressive Boost libraries such as Boost.Lambda or Boost.Phoenix which go a long way towards making C++ into a truly functional language. But is there a straightforward way to create a composite function from any 2 or more arbitrary functions or functors?
If I have: int f(int x) and int g(int x), I want to do something like f . g which would statically generate a new function object equivalent to f(g(x)).
This seems to be possible through various techniques, such as those discussed here. Certainly, you can chain calls to boost::lambda::bind to create a composite functor. But is there anything in Boost which easily allows you to take any 2 or more functions or function objects and combine them to create a single composite functor, similar to how you would do it in a language like Haskell?

To anyone stumbling onto this page, there's a great blog post on this subject from bureau14:
http://blog.quasardb.net/function-composition-in-c11/
This takes advantage of the new features in C++ 11 as well as using boost.

Stumbling upon this question, I'd like to point out to anyone who comes across this today that this is possible with a relatively elegant syntax using just the standard library and a few helper classes thanks to decltype, auto, and perfect forwarding.
Defining these two classes:
template <class Arg, class ArgCall, class OuterCall>
class pipe {
private:
ArgCall argcall;
OuterCall outercall;
public:
typedef pipe<Arg, ArgCall, OuterCall> this_type;
pipe(ArgCall ac, OuterCall oc) : argcall(ac), outercall(oc) {}
auto operator()(Arg arg) -> decltype(outercall(argcall(arg))) {
return outercall(argcall(arg));
}
template <class NewCall>
pipe<Arg, this_type, NewCall> operator[](NewCall&& nc) {
return {*this, std::forward<NewCall>(nc)};
}
};
template <class Arg>
class pipe_source {
public:
typedef pipe_source<Arg> this_type;
Arg operator()(Arg arg) {
return arg;
}
template <class ArgCall, class OuterCall>
static pipe<Arg, ArgCall, OuterCall> create(ArgCall&& ac, OuterCall&& oc) {
return {std::forward<ArgCall>(ac), std::forward<OuterCall>(oc)};
}
template <class OuterCall>
pipe<Arg, this_type, OuterCall> operator[](OuterCall&& oc) {
return {*this, std::forward<OuterCall>(oc)};
}
};
A simple program:
int f(int x) {
return x*x;
}
int g(int x) {
return x-2;
}
int h(int x) {
return x/2;
}
int main() {
auto foo = pipe_source<int>::create(f, g);
//or:
auto bar = pipe_source<int>()[g][h];
std::cout << foo(10) << std::endl;
std::cout << bar(10) << std::endl;
return 0;
}
This has the added benefit that once it's in a pipe, as long as the return type is correct you can add another function f to the chain with pipe[f].
Then:
$ g++ test.cpp -o test -std=c++11
$ ./test
98
4
$

I don't know of anything that supports the syntax you wish for currently. However, it would be a simple matter to create one. Simply override * for functors (boost::function<> for example) so that it returns a composite functor.
template < typename R1, typename R2, typename T1, typename T2 >
boost::function<R1(T2)> operator * (boost::function<R1(T2)> const& f, boost::function<R2(T2)> const& g)
{
return boost::bind(f, boost::bind(g, _1));
}
Untested, but I suspect it's close if it doesn't work out of the box.

Template them.
template<typename T1> class FunctorOne {
FunctorOne(T1 newt)
: t(newt) {}
void operator()() {
t();
}
T1 t;
};
template<> class FunctorOne<void> {
void operator()() {
}
};
template<typename T1> class FunctorTwo {
FunctorOne(T1 newt)
: t(newt) {}
void operator()() {
t();
}
T1 t;
};
template<> class FunctorTwo<void> {
void operator()() {
}
};
FunctorOne<FunctorTwo<FunctorOne<FunctorTwo<void>>>>> strangefunctionobject(FunctorTwo(FunctorOne(FunctorTwo()));
Excellent use of typedefs is recommended.
Edit: Whoops. Turns out that type inference in constructors sucks. I'll get back in a minute with something that actually works :P
Even more edit:
If you wanted just functors rather than functionoids, you could just create a new instance, or even just use static functions.
template<typename T1, typename T2> class FunctorOne {
public:
static bool Call() {
T1::Call(T2::Call());
return true;
}
};
template<> class FunctorOne<void, void> {
public:
static bool Call() {
}
};
template<typename T1> class FunctorTwo {
public:
static bool Call() {
T1::Call();
}
};
template<> class FunctorTwo<void> {
public:
static bool Call() {
}
};
bool haicakes = FunctorOne<FunctorTwo<void>, FunctorTwo<void>>::Call();
This assumes that in any given function, you can handle each different signature somewhat manually. Use of decltype could help in this regard with a C++0x compiler.

C++11. No boost. No helper classes. Any amount of arguments. Just std::function and variadic templates.
template <typename F1, typename F2>
struct function_composition_traits : public function_composition_traits<decltype(&F1::operator()), decltype(&F2::operator())>
{};
template <typename ClassType1, typename ReturnType1, typename... Args1, typename ClassType2, typename ReturnType2, typename... Args2>
struct function_composition_traits<ReturnType1(ClassType1::*)(Args1...) const, ReturnType2(ClassType2::*)(Args2...) const>
{
typedef std::function<ReturnType2(Args1...)> composition;
template <typename Func1, typename Func2>
inline static composition compose(const Func1& f1, const Func2& f2) {
return [f1,f2](Args1... args) -> ReturnType2 { return f2(f1(std::forward<Args1>(args)...)); };
}
};
template <typename F1, typename F2>
typename function_composition_traits<F1,F2>::composition compose(const F1& lambda1,const F2& lambda2)
{
return function_composition_traits<F1,F2>::template compose<F1,F2>(lambda1, lambda2);
}
template <typename F, typename... Fs>
auto compose(F f, Fs... fs) -> decltype(compose(f, compose(fs...)))
{
return compose(f, compose(std::forward<Fs>(fs)...));
}
Usage:
auto add = [](int x, int y){ return x+y; };
auto mul = [](int x){ return x*2; };
auto divide = [](int x) { return (double)x / 3.0; };
auto test = compose(add, mul, divide);
cout << "Result: " << test(2,3);
Output:
Result: 3.33333

See this answer https://stackoverflow.com/a/27727236/286335.
Really short, easy and general.

Related

Specializing function template based on lambda arity

I am trying to specialize a templated function based on the arity of the lambda that I pass to it as an argument. This is what I have come up with for a solution:
template<typename Function, bool>
struct helper;
template<typename Function>
struct helper<Function, false>
{
auto operator()(Function&& func)
{
std::cout << "Called 2 argument version.\n";
return func(1, 2);
}
};
template<typename Function>
struct helper<Function, true>
{
auto operator()(Function&& func)
{
std::cout << "Called 3 argument version.\n";
return func(1, 2, 3);
}
};
template<typename T>
struct B
{
T a;
const T someVal() const { return a; }
};
template<typename Function, typename T>
auto higherOrderFun(Function&& func, const T& a)
{
return helper<Function, std::is_invocable<Function, decltype(a.someVal()), decltype(a.someVal()), decltype(a.someVal())>::value>{}(std::forward<Function>(func));
}
int main()
{
B<int> b;
std::cout << higherOrderFun([](auto x, auto y) {return x+y; }, b) << "\n";
std::cout << higherOrderFun([](auto x, auto y, auto z) {return x + y+z; }, b) << "\n";
return 0;
}
Is there a way to achieve this in a more elegant manner? I've looked through this: Arity of a generic lambda
However, the latest solution (florestan's) turns all arguments into aribtrary_t, so one has to cast them back inside of each lambda, which I do not find ideal. Ideally I would have liked to directly specialize the templated higherOrderFun with SFINAE, but as it is I use a helper class in order to achieve that. Is there a more straighforward way? For instance to apply SFINAE directly to higherOrderFun without relying on a helper class? The whole point of this is to not have to change higherOrderFun into higherOrderFun2 and higherOrderFun3, but rather have the compiler deduce the correct specialization from the lambda and the given argument (const T& a).
I should mention that I also don't care about the type of the arguments to the function - just about their count, so I would have changed decltype(a.someVal()) to auto in my example if that was possible (maybe there's a way to circumvent explicitly defining the types?).
The following template gives me the number of parameters to a lambda, a std::function, or a plain function pointer. This seems to cover all the basics. So, you specialize on n_lambda_parameters<T>::n, and plug this into your template. Depending on your specific use cases, you may need to employ the facilities offered by std::remove_reference_t or std::decay_t, to wrap this.
Tested with g++ 9. Requires std::void_t from C++17, plenty of examples of simulating std::void_t pre C++17 can be found elsewhere...
#include <functional>
// Plain function pointer.
template<typename T> struct n_func_parameters;
template<typename T, typename ...Args>
struct n_func_parameters<T(Args...)> {
static constexpr size_t n=sizeof...(Args);
};
// Helper wrapper to tease out lambda operator()'s type.
// Tease out closure's operator()...
template<typename T, typename> struct n_extract_callable_parameters;
// ... Non-mutable closure
template<typename T, typename ret, typename ...Args>
struct n_extract_callable_parameters<T, ret (T::*)(Args...) const> {
static constexpr size_t n=sizeof...(Args);
};
// ... Mutable closure
template<typename T, typename ret, typename ...Args>
struct n_extract_callable_parameters<T, ret (T::*)(Args...)> {
static constexpr size_t n=sizeof...(Args);
};
// Handle closures, SFINAE fallback to plain function pointers.
template<typename T, typename=void> struct n_lambda_parameters
: n_func_parameters<T> {};
template<typename T>
struct n_lambda_parameters<T, std::void_t<decltype(&T::operator())>>
: n_extract_callable_parameters<T, decltype(&T::operator())> {};
#include <iostream>
void foo(int, char, double=0)
{
}
int main()
{
auto closure=
[](int x, int y)
// With or without mutable, here.
{
};
std::cout << n_lambda_parameters<decltype(closure)>::n
<< std::endl; // Prints 2.
std::cout << n_lambda_parameters<decltype(foo)>::n
<< std::endl; // Prints 3.
std::cout << n_lambda_parameters<std::function<void (int)>>::n
<< std::endl; // Prints 1.
return 0;
}
I would use different overloads:
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2, 3))
{
return std::forward<Function>(func)(1, 2, 3);
}
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
Possibly with overload priority as
struct low_priority {};
struct high_priority : low_priority{};
template<typename Function>
auto higherOrderFunImpl(Function&& func, low_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
template<typename Function>
auto higherOrderFunImpl(Function&& func, high_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
return std::forward<Function>(func)(1, 2);
}
template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(higherOrderFun(std::forward<Function>(func), high_priority{}))
{
return higherOrderFun(std::forward<Function>(func), high_priority{});
}
If you want to use the arity traits from florestan, it might result in:
template<typename F>
decltype(auto) higherOrderFun(F&& func)
{
if constexpr (arity_v<std::decay_t<F>, MaxArity> == 3)
{
return std::forward<F>(func)(1, 2, 3);
}
else if constexpr (arity_v<std::decay_t<F>, MaxArity> == 2)
{
return std::forward<F>(func)(1, 2);
}
// ...
}

Specializing templates based on methods

Recently I've been programming a lot in Java, now I'm coming back to my C++ roots (I really started missing the pointers and segmentation faults). Knowing that C++ has a broad support for templates I was wondering whether it has some capabilities of Java which could be useful for writing generalized code. Lets say I'have two groups of classes. One of them has the first() method, the other one has the second() method. Is there a way of specializing the templates to be picked by the compiler depending on the methods one class possesses? I'm aiming at behavior which is similar to the one of Java:
public class Main {
public static void main(String[] args) {
First first = () -> System.out.println("first");
Second second = () -> System.out.println("second");
method(first);
method(second);
}
static <T extends First> void method(T argument) {
argument.first();
}
static <T extends Second> void method(T argument) {
argument.second();
}
}
Where First and Second are interfaces. I know I could group both of these groups by deriving each of them from an upper class, but it's not always possible (no autoboxing in C++ and some classes don't inherit from a common ancestor).
A good example of my needs is the STL library, where some classes have methods like push() and some others have insert() or push_back(). Lets say I want to create an function which has to insert multiple values into an container using an variadic function. In Java it's easy to perform because collections have a common ancestor. In C++ on the other hand it's not always the case. I tried it by duck-typing, but the compiler yields an error message:
template <typename T>
void generic_fcn(T argument) {
argument.first();
}
template <typename T>
void generic_fcn(T argument) {
argument.second();
}
So my question is: Is implementing such behavior possible without creating unnecessary boileplate code by specializing every single case?
Instead of <T extends First>, you will use something we call sfinae. This is a technique about adding constaints on a function based on parameter types.
Here's how you'd do it in c++:
template <typename T>
auto generic_fcn(T argument) -> void_t<decltype(argument.first())> {
argument.first();
}
template <typename T>
auto generic_fcn(T argument) -> void_t<decltype(argument.second())> {
argument.second();
}
For the function to exist, the compiler will need the type of argument.second() or the type of argument.first(). If the expression does not yield a type (ie. T has not a first() function), the compiler will try another overload.
void_t is implemented as follow:
template<typename...>
using void_t = void;
Another great thing is that if you have such class:
struct Bummer {
void first() {}
void second() {}
};
Then the compiler will effectively tell you that the call is ambiguous because the type match both constraints.
If you really want to test if a type extends another (or implement, in c++ it's the same thing) you can use the type trait std::is_base_of
template <typename T>
auto generic_fcn(T argument) -> std::enable_if_t<std::is_base_of<First, T>::value> {
argument.first();
}
template <typename T>
auto generic_fcn(T argument) -> std::enable_if_t<std::is_base_of<Second, T>::value> {
argument.second();
}
To read more about this topic, check sfinae on cpprefence, and you can check available traits provided by the standard library.
so many options available in c++.
My preference is to favour free functions and return any result type correctly.
#include <utility>
#include <type_traits>
#include <iostream>
struct X
{
int first() { return 1; }
};
struct Y
{
double second() { return 2.2; }
};
//
// option 1 - specific overloads
//
decltype(auto) generic_function(X& x) { return x.first(); }
decltype(auto) generic_function(Y& y) { return y.second(); }
//
// option 2 - enable_if
//
namespace detail {
template<class T> struct has_member_first
{
template<class U> static auto test(U*p) -> decltype(p->first(), void(), std::true_type());
static auto test(...) -> decltype(std::false_type());
using type = decltype(test(static_cast<T*>(nullptr)));
};
}
template<class T> using has_member_first = typename detail::has_member_first<T>::type;
namespace detail {
template<class T> struct has_member_second
{
template<class U> static auto test(U*p) -> decltype(p->second(), void(), std::true_type());
static auto test(...) -> decltype(std::false_type());
using type = decltype(test(static_cast<T*>(nullptr)));
};
}
template<class T> using has_member_second = typename detail::has_member_second<T>::type;
template<class T, std::enable_if_t<has_member_first<T>::value>* =nullptr>
decltype(auto) generic_func2(T& t)
{
return t.first();
}
template<class T, std::enable_if_t<has_member_second<T>::value>* =nullptr>
decltype(auto) generic_func2(T& t)
{
return t.second();
}
//
// option 3 - SFNAE with simple decltype
//
template<class T>
auto generic_func3(T&t) -> decltype(t.first())
{
return t.first();
}
template<class T>
auto generic_func3(T&t) -> decltype(t.second())
{
return t.second();
}
int main()
{
X x;
Y y;
std::cout << generic_function(x) << std::endl;
std::cout << generic_function(y) << std::endl;
std::cout << generic_func2(x) << std::endl;
std::cout << generic_func2(y) << std::endl;
std::cout << generic_func3(x) << std::endl;
std::cout << generic_func3(y) << std::endl;
}
You can dispatch the call as it follows:
#include<utility>
#include<iostream>
struct S {
template<typename T>
auto func(int) -> decltype(std::declval<T>().first(), void())
{ std::cout << "first" << std::endl; }
template<typename T>
auto func(char) -> decltype(std::declval<T>().second(), void())
{ std::cout << "second" << std::endl; }
template<typename T>
auto func() { return func<T>(0); }
};
struct First {
void first() {}
};
struct Second {
void second() {}
};
int main() {
S s;
s.func<First>();
s.func<Second>();
}
Method first is preferred over second if a class has both of them.
Otherwise, func uses function overloading to test the two methods and choose the right one.
This technique is called sfinae, use this name to search on the web for further details.
Here is a little library that helps you determine if a member exists.
namespace details {
template<template<class...>class Z, class always_void, class...>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z, void, Ts...>;
Now we can write has first and has second easily:
template<class T>
using first_result = decltype(std::declval<T>().first());
template<class T>
using has_first = can_apply<first_result, T>;
and similarly for second.
Now we have our method. We want to call either first or second.
template<class T>
void method_second( T& t, std::true_type has_second ) {
t.second();
}
template<class T>
void method_first( T& t, std::false_type has_first ) = delete; // error message
template<class T>
void method_first( T& t, std::true_type has_first ) {
t.first();
}
template<class T>
void method_first( T& t, std::false_type has_first ) {
method_second( t, has_second<T&>{} );
}
template<class T>
void method( T& t ) {
method_first( t, has_first<T&>{} );
}
this is known as tag dispatching.
method calls the method_first which is determined if T& can be invoked with .first(). If it can be, it calls the one that calls .first().
If it cannot, it calls the one that forwards to method_second and tests if it has .second().
If it has neither, it calls an =delete function, which generates an error message at compile time.
There are many, many, many ways to do this. I personally like tag dispatching because you can get better error messages out of failure to match than SFIANE generates.
In C++17 you can be more direct:
template<class T>
void method(T & t) {
if constexpr (has_first<T&>{}) {
t.first();
}
if constexpr (has_second<T&>{}) {
t.second();
}
}

Achieve functor overloading through composition

Given some existing functors:
struct incr {
int operator()(int x) const { return x + 1; }
};
struct rep_str {
std::string operator()(const std::string& s) const { return s + s; }
};
I'm wondering if it's possible to achieve something like this:
auto f = overload<incr, rep_str>();
f(1); // returns 2
f("hello"); // returns "hellohello"
Multiple overloads may look like:
auto f = overload<fa, fb, fc, ...>();
// or...
auto g = overload<fa, overload<fb, overload<fc, ...>>>();
I'm thinking maybe use SFINAE with std::result_of_t or something like that, but haven't figured out how.
You don't need anything too fancy: just inherit from all the arguments and use using-declarations to bring in operator() from the base classes. However, in the variadic case, you can't have a pack expansion in a using-declaration, so you have to use a recursive approach, like so:
template <class... Ts>
struct overload {}; // only used for empty pack
template <class T>
struct overload<T> : private T {
using T::operator();
};
template <class T1, class T2, class... Ts>
struct overload<T1, T2, Ts...> : private T1, overload<T2, Ts...> {
using T1::operator();
using overload<T2, Ts...>::operator();
};
Brian's answer is better, IMHO, but since I worked on it, here's mine:
#include <type_traits>
#include <utility>
template <typename... Fns>
struct overload;
template <typename Fn, typename... Fns>
struct overload<Fn, Fns...>
{
template <typename... T>
std::result_of_t<Fn(T...)> operator()(T && ... args) const {
return Fn()(std::forward<T>(args)...);
}
using next = overload<Fns...>;
template <typename... T>
std::result_of_t<next(T...)> operator()(T && ... args) const {
return next()(std::forward<T>(args)...);
}
};
this can be done using template specialization:
#include <string>
#include <iostream>
template <typename...Args>
struct overload{
};
template <> struct overload<int>{
int operator()(int x) const { return x + 1; }
};
template <> struct overload< std::string>{
std::string operator()(const std::string& s) const { return s + s; }
};
template <typename...Args >
auto f(Args...arg){
overload<Args...> func;
return func(arg...);
}
int main()
{
std::cout << f(3) << std::endl << f(std::string("Hello"));
}
Note: two answers by #Brian and #md5i more general and elegant and perfect and better than this.

Passing Template Variable to Template Function in C++14

I'm writing a compiler that compiles to C++ and am having type issues with my C++ code. The language is meant to be lazy, so we have a lazy value wrapper, Chunk. Here is a part of it, along with the problematic code:
#include <functional>
#include <memory>
template<class T>
class Chunk
{
public:
Chunk();
Chunk(std::function<T()> f);
T operator()();
std::function<T()> f_;
private:
std::shared_ptr<T> cache_;
};
template<class T>
T Chunk<T>::operator()()
{
if(cache_ == nullptr)
cache_ = std::make_shared<T>(f_());
return *cache_;
}
template<class T, class F>
T operator*(Chunk<T> t1, Chunk<F> t2)
{
return t1() * t2();
}
template<class T, class... Args>
T apply(Chunk<std::function<T(Args...)>> c, Args... as)
{
return c()(as...);
}
template<class F>
auto toChunk(F f) -> Chunk<decltype(f())>
{
return Chunk<decltype(f())>(f);
}
template<class T, class F>
struct ops
{
static const auto multiply =
toChunk([]() { return ops::multiply_; });
static const auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
};
int main()
{
Chunk<double> t = toChunk([]() { return 1.0; });
Chunk<float> f = toChunk([]() { return 2.0f; });
apply(ops::multiply, t, f);
return 0;
}
I can't figure out a definition of multiply to make this work without getting a used without template parameters error. (There may be a second issue here because multiply_ isn't a std::function, but the compiler breaks on the lack of template parameters first.)
I could write a lot of overloads for every pair of types, but this is just really ugly. I tried making multiply a template variable without a template class, and even though I'm using C++14, got cannot resolve address of overloaded function at multiply_ with this alternative definition:
template<class T, class F>
auto multiply_(Chunk<T> x, Chunk<F> y) -> decltype(x * y)
{
return x * y;
}
template<class T, class F>
Chunk<decltype(multiply_)> multiply = toChunk([]() { return multiply_; });
Of course I then changed ops::multiply to simply multiply. Any suggestions to overcome this?
ops is a name of a class template. To refer to members of a class template outside of its definition you need to specify the template arguments.
If you fix this error though, there are going to be more.
I ended up using an entirely different solution. I overloaded apply by adding this second definition:
template<class F, class... Args>
auto apply(F f, Args... as) -> decltype(f(as...))
{
return f(as...);
}
And rewrote multiply as simply:
auto multiply = [](auto x, auto y) { return x * y; };
So our library functions will not be in the lazy wrappers, while user-defined functions (which can't be templates in our language) will.

5 years later, is there something better than the "Fastest Possible C++ Delegates"?

I know that the topic of "C++ delegates" has been done to death, and both http://www.codeproject.com and http://stackoverflow.com deeply cover the question.
Generally, it seems that Don Clugston's fastest possible delegate is the first choice for many people. There are a few other popular ones.
However, I noticed that most of those articles are old (around 2005) and many design choices seem to have been made taking in account old compilers like VC7.
I'm in need of a very fast delegate implementation for an audio application.
I still need it to be portable (Windows, Mac, Linux) but I only use modern compilers (VC9, the one in VS2008 SP1 and GCC 4.5.x).
My main criteria are:
it must be fast!
it must be forward-compatible with newer versions of the compilers. I have some doubts about that with Don's implementation because he explicitly states it's not standard-compliant.
optionally, a KISS-syntax and ease-of-use is nice to have
multicast would be nice, although I'm convinced it's really easy to build it around any delegate library
Furthermore, I don't really need exotic features. I just need the good old pointer-to-method thing. No need to support static methods, free functions or things like that.
As of today, what is the recommended approach? Still use Don's version?
Or is there a "community consensus" about another option?
I really don't want to use Boost.signal/signal2 because it's not acceptable in terms of performance. A dependency on QT is not acceptable as well.
Furthermore, I've seen some newer libraries while googling, like for example cpp-events but I couldn't find any feedback from users, including on SO.
Update: An article with the complete source code and a more detailed discussion has been posted on The Code Project.
Well, the problem with pointers to methods is that they're not all the same size. So instead of storing pointers to methods directly, we need to "standardize" them so that they are of a constant size. This is what Don Clugston attempts to achieve in his Code Project article. He does so using intimate knowledge of the most popular compilers. I assert that it's possible to do it in "normal" C++ without requiring such knowledge.
Consider the following code:
void DoSomething(int)
{
}
void InvokeCallback(void (*callback)(int))
{
callback(42);
}
int main()
{
InvokeCallback(&DoSomething);
return 0;
}
This is one way to implement a callback using a plain old function pointer. However, this doesn't work for methods in objects. Let's fix this:
class Foo
{
public:
void DoSomething(int) {}
static void DoSomethingWrapper(void* obj, int param)
{
static_cast<Foo*>(obj)->DoSomething(param);
}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f), &Foo::DoSomethingWrapper);
return 0;
}
Now, we have a system of callbacks that can work for both free and member functions. This, however, is clumsy and error-prone. However, there is a pattern - the use of a wrapper function to "forward" the static function call to a method call on the proper instance. We can use templates to help with this - let's try generalizing the wrapper function:
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(void* instance, void (*callback)(void*, int))
{
callback(instance, 42);
}
int main()
{
Foo f;
InvokeCallback(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething> );
return 0;
}
This is still extremely clumsy, but at least now we don't have to write out a wrapper function every single time (at least for the 1 argument case). Another thing we can generalize is the fact that we're always passing a pointer to void*. Instead of passing it as two different values, why not put them together? And while we're doing that, why not generalize it as well? Hey, let's throw in an operator()() so we can call it like a function!
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1, R (T::*Func)(A1)>
R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
Callback<void, int> cb(static_cast<void*>(&f),
&Wrapper<void, Foo, int, &Foo::DoSomething>);
InvokeCallback(cb);
return 0;
}
We're making progress! But now our problem is the fact that the syntax is absolutely horrible. The syntax appears redundant; can't the compiler figure out the types from the pointer to method itself? Unfortunately no, but we can help it along. Remember that a compiler can deduce types via template argument deduction in a function call. So why don't we start with that?
template<typename R, class T, typename A1>
void DeduceMemCallback(R (T::*)(A1)) {}
Inside the function, we know what R, T and A1 is. So what if we can construct a struct that can "hold" these types and return them from the function?
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag2<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
And since DeduceMemCallbackTag knows about the types, why not put our wrapper function as a static function in it? And since the wrapper function is in it, why not put the code to construct our Callback object in it?
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
The C++ standard allows us to call static functions on instances (!):
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(
DeduceMemCallback(&Foo::DoSomething)
.Bind<&Foo::DoSomething>(&f)
);
return 0;
}
Still, it's a lengthy expression, but we can put that into a simple macro (!):
template<typename R, typename A1>
class Callback
{
public:
typedef R (*FuncType)(void*, A1);
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
private:
void* obj;
FuncType func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R, A1> Bind(T* o)
{
return Callback<R, A1>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
class Foo
{
public:
void DoSomething(int) {}
};
void InvokeCallback(Callback<void, int> callback)
{
callback(42);
}
int main()
{
Foo f;
InvokeCallback(BIND_MEM_CB(&Foo::DoSomething, &f));
return 0;
}
We can enhance the Callback object by adding a safe bool. It's also a good idea to disable the equality operators since it's not possible to compare two Callback objects. Even better, is to use partial specialization to allow for a "preferred syntax". This gives us:
template<typename FuncSignature>
class Callback;
template<typename R, typename A1>
class Callback<R (A1)>
{
public:
typedef R (*FuncType)(void*, A1);
Callback() : obj(0), func(0) {}
Callback(void* o, FuncType f) : obj(o), func(f) {}
R operator()(A1 a1) const
{
return (*func)(obj, a1);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const
{
return func != 0? &Callback::obj : 0;
}
bool operator!() const
{
return func == 0;
}
private:
void* obj;
FuncType func;
};
template<typename R, typename A1> // Undefined on purpose
void operator==(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, typename A1>
void operator!=(const Callback<R (A1)>&, const Callback<R (A1)>&);
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag
{
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1)
{
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R (A1)> Bind(T* o)
{
return Callback<R (A1)>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1))
{
return DeduceMemCallbackTag<R, T, A1>();
}
#define BIND_MEM_CB(memFuncPtr, instancePtr) \
(DeduceMemCallback(memFuncPtr).Bind<(memFuncPtr)>(instancePtr))
Usage example:
class Foo
{
public:
float DoSomething(int n) { return n / 100.0f; }
};
float InvokeCallback(int n, Callback<float (int)> callback)
{
if(callback) { return callback(n); }
return 0.0f;
}
int main()
{
Foo f;
float result = InvokeCallback(97, BIND_MEM_CB(&Foo::DoSomething, &f));
// result == 0.97
return 0;
}
I have tested this on the Visual C++ compiler (version 15.00.30729.01, the one that comes with VS 2008), and you do need a rather recent compiler to use the code. By inspection of the disassembly, the compiler was able to optimize away the wrapper function and the DeduceMemCallback call, reducing down to simple pointer assignments.
It's simple to use for both sides of the callback, and uses only (what I believe to be) standard C++. The code I've shown above works for member functions with 1 argument, but can be generalized to more arguments. It can also be further generalized by allowing support for static functions.
Note that the Callback object requires no heap allocation - they are of a constant size thanks to this "standardization" procedure. Because of this, it's possible to have a Callback object be a member of larger class, since it has a default constructor. It is also assignable (the compiler generated copy assignment functions are sufficient). It is also typesafe, thanks to the templates.
I wanted to follow off of #Insilico's answer with a bit of my own stuff.
Before I had stumbled upon this answer, I was trying to figure out fast callbacks as well that incurred no overhead and were uniquely comparable / identified by function signature only. What I ended up creating - with some serious help from Klingons Who Happened To Be at a BBQ - works for all function types (except Lambdas, unless you store the Lambda, but don't try it because it's really difficult and hard to do and may result in a robot proving to you how difficult it is and making you eat the shit for it). Thanks to #sehe, #nixeagle, #StackedCrooked, #CatPlusPlus, #Xeo, #DeadMG and of course #Insilico for the help in creating the event system. Feel free to use as you desire.
Anyway, an example is up on ideone, but the source code is also here for your use (because, since Liveworkspace went down, I don't trust them shady compiling services. Who knows when ideone will go down?!). I hope this is useful for somebody who's not busy Lambda/Function-objecting the world to pieces:
IMPORTANT NOTE: As of right now (28/11/2012, 9:35 PM) This variadic version will not work with the Microsoft VC++ 2012 November CTP (Milan). If you want to use it with that, you will have to get rid of all the variadic stuff and explicitly enumerate the number of arguments (and possibly template-specialize the 1-argument type for Event for void) to make it work. It's a pain, and I could only manage to write it out for 4 arguments before I got tired (and decided that passing more than 4 arguments was a bit of a stretch).
Source Example
Source:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
template<typename TFuncSignature>
class Callback;
template<typename R, typename... Args>
class Callback<R(Args...)> {
public:
typedef R(*TFunc)(void*, Args...);
Callback() : obj(0), func(0) {}
Callback(void* o, TFunc f) : obj(o), func(f) {}
R operator()(Args... a) const {
return (*func)(obj, std::forward<Args>(a)...);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType() const {
return func? &Callback::obj : 0;
}
bool operator!() const {
return func == 0;
}
bool operator== (const Callback<R (Args...)>& right) const {
return obj == right.obj && func == right.func;
}
bool operator!= (const Callback<R (Args...)>& right) const {
return obj != right.obj || func != right.func;
}
private:
void* obj;
TFunc func;
};
namespace detail {
template<typename R, class T, typename... Args>
struct DeduceConstMemCallback {
template<R(T::*Func)(Args...) const> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, class T, typename... Args>
struct DeduceMemCallback {
template<R(T::*Func)(Args...)> inline static Callback<R(Args...)> Bind(T* o) {
struct _ { static R wrapper(void* o, Args... a) { return (static_cast<T*>(o)->*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(o, (R(*)(void*, Args...)) _::wrapper);
}
};
template<typename R, typename... Args>
struct DeduceStaticCallback {
template<R(*Func)(Args...)> inline static Callback<R(Args...)> Bind() {
struct _ { static R wrapper(void*, Args... a) { return (*Func)(std::forward<Args>(a)...); } };
return Callback<R(Args...)>(0, (R(*)(void*, Args...)) _::wrapper);
}
};
}
template<typename R, class T, typename... Args>
detail::DeduceConstMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...) const) {
return detail::DeduceConstMemCallback<R, T, Args...>();
}
template<typename R, class T, typename... Args>
detail::DeduceMemCallback<R, T, Args...> DeduceCallback(R(T::*)(Args...)) {
return detail::DeduceMemCallback<R, T, Args...>();
}
template<typename R, typename... Args>
detail::DeduceStaticCallback<R, Args...> DeduceCallback(R(*)(Args...)) {
return detail::DeduceStaticCallback<R, Args...>();
}
template <typename... T1> class Event {
public:
typedef void(*TSignature)(T1...);
typedef Callback<void(T1...)> TCallback;
typedef std::vector<TCallback> InvocationTable;
protected:
InvocationTable invocations;
public:
const static int ExpectedFunctorCount = 2;
Event() : invocations() {
invocations.reserve(ExpectedFunctorCount);
}
template <void (* TFunc)(T1...)> void Add() {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>();
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...)> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T& object) {
Add<T, TFunc>(&object);
}
template <typename T, void (T::* TFunc)(T1...) const> void Add(T* object) {
TCallback c = DeduceCallback(TFunc).template Bind<TFunc>(object);
invocations.push_back(c);
}
void Invoke(T1... t1) {
for(size_t i = 0; i < invocations.size() ; ++i) invocations[i](std::forward<T1>(t1)...);
}
void operator()(T1... t1) {
Invoke(std::forward<T1>(t1)...);
}
size_t InvocationCount() { return invocations.size(); }
template <void (* TFunc)(T1...)> bool Remove ()
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>()); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...)> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T& object)
{ return Remove <T, TFunc>(&object); }
template <typename T, void (T::* TFunc)(T1...) const> bool Remove (T* object)
{ return Remove (DeduceCallback(TFunc).template Bind<TFunc>(object)); }
protected:
bool Remove( TCallback const& target ) {
auto it = std::find(invocations.begin(), invocations.end(), target);
if (it == invocations.end())
return false;
invocations.erase(it);
return true;
}
};