Function composition using std::bind
A very interesting question. I can identify two main differences between your implementation (using variadic templates) and the linked article's implementation (using Boost.Fusion):


The definition of function composition. A call to your make_composite_function(f1, f2, f3)(x) is semantically equivalent to f1(f2(f3(x))). Calling the linked article's compose(f1, f2, f3) is semantically equivalent to f3(f2(f1(x))).

Which definition is more natural is completely up to the reader. Both are perfectly valid. Your make_composite_function has the nice property that it is very easy to implement with variadic templates (since the recursion uses "pop front" logic). This is actually mentioned as an alternative in the linked article.

Furthermore, they argue for their definition of function composition because it follows the reading direction. E.g., compose(receive, decode, store)(data) is semantically equivalent to store(decode(receive(data))) which follows the expected behaviour of first receiving data, then decoding it, and finally storing it. To get the same semantics with your definition, we would have to write make_composite_function(store, decode, receive). Again, this does the same thing but is arguably harder to decipher during a cursory read-through.

Alas, the linked article goes through a world of trouble to get that "pop back" recursion logic to work (using Boost.Fusion). So they do as they do not because they are oblivious of variadic templates but because variadic recursion simply doesn't cut it. Here's a quote from the article:


  Variadic templates unfortunately work in a "pop front" logic, making the code actually much less straightforward (because these unintelligible recursive preprocessor macros are obviously mundane). You could nevertheless write a pop front variadic template version with an adapter that reverses the list of parameters.


Note the proposed alternative implementation using a reversion adaptor. That would be a nice C++ exercise. I wonder how that would compare complexity-wise.
The linked article's implementation supports std::tuple arguments such as compose(std::make_tuple(f1, f2, f3)). Yours don't. Of course, this adds extra complexity to their implementation compared to yours. There's not much more to say on this point.


To sum up, the difference in complexity is because you seek different interfaces. Both interfaces are valid and work. Which one is more natural depends on the application.

Edit: Here is a code sample of your version. Note that I just use auto return type deduction (as you suggested yourself in the code comment).