![]() |
Home | Libraries | People | FAQ | More |
Much has already been written about dispatching on type traits using SFINAE (Substitution Failure Is Not An Error) techniques in C++. There is a Boost library, Boost.Enable_if, to make the technique idiomatic. Proto dispatches on type traits extensively, but it doesn't use enable_if<> very often. Rather, it dispatches based on the presence or absence of nested types, often typedefs for void.
Consider the implementation of is_expr<>. It could have been written as something like this:
template<typename T> struct is_expr : is_base_and_derived<proto::some_expr_base, T> {};
Rather, it is implemented as this:
template<typename T, typename Void = void> struct is_expr : mpl::false_ {}; template<typename T> struct is_expr<T, typename T::proto_is_expr_> : mpl::true_ {};
This relies on the fact that the specialization will be preferred if T has a nested proto_is_expr_ that is a typedef for void. All Proto expression types have such a nested typedef.
Why does Proto do it this way? The reason is because, after running extensive benchmarks while trying to improve compile times, I have found that this approach compiles faster. It requires exactly one template instantiation. The other approach requires at least 2: is_expr<> and is_base_and_derived<>, plus whatever templates is_base_and_derived<> may instantiate.