Curried type traits
Partial meta function application is critically useful. For example, if you want to test a list of types whether they are implicitly convertible to a known type T, basically you need to "bind" T to is_convertible. With Boost.MPL, it would be:
using F = std::is_convertible<mpl::_1, T>;
_1 is a meta placeholder[1], which is conceptually same as that to std::bind, but works with meta functions. However, while the result of std::bind still supports operator(), now the F above can only be called with mpl::apply<F, Arg>. Such a calling convention change also affects meta algorithms' implementation. Although Boost handles it very well, it can hardly be a cross-library solution.
Here is a simple thought: use currying[2] instead of partial application. Currying starts with a simple interpretation of a multi-argument function:
f(a, b, c, ...) => f(a)(b)(c)...
In the world of currying, there are only unary functions, and a multi-argument function is just a function returning another unary function, and applying such a function, in effect, is to bind an argument. Mapping these to C++, I get:
is_constructible<T1, T2, T3> => curried<is_constructible, 3>::call<T1>::call<T2>::call<T3>
The second argument of curried is the number of arguments you want to curry; defaults to 2. There we have the construct to make any argument "free to bind", and the next step is to make an argument at any position "ready to bind":
flipped<curried<F, 3>, 3>:call<T3>::call<T1>::call<T2>
flipped switches the Nth argument of a curried function to the next call position; N defaults to 2 (you may have noticed that these two functions are just generalized curry and flip in Haskell). Now we are able to bind any argument, any where.
The last issue is that a meta algorithm might expect normal multi-argument functions, not curried ones. Basically, we need uncurry. Here is the shining part: wherever useful, there is an ::apply typedef in addition to ::call to give you the "automatically" uncurried meta function:
flipped<curried<F, 3>, 3>:call<T3>::apply<T1, T2>
Now the advantage of this system is quite clear: the calling convention is not changed -- after done processing the meta function, ::apply or ::call is just the processed meta function. For the example at the beginning, it would be
using F = flipped<curried<std::is_convertible>>::call<T>;
, then drop F::call to wherever need a template. If you want to know more, here is a tiny meta programming library[3] I wrote based on this system.
Links:
[1] Handling Placeholders, from "A Deeper Look at Metafunctions". http://www.artima.com/cppsource/metafunctions2.html
[2] Currying. https://en.wikipedia.org/wiki/Currying
[3] C++ traits adaptors. https://github.com/lichray/traits_adaptors













