![]() |
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.