I am confused about the advantages of using the the
bool_<true>
and
bool_<false>
types against simply using const bools in the context of template metaprogramming.
The boost::mpl library clearly prefers the first approach, and defines helper functions like and_, or_ to help manage such bool_. Conditional metafunctions like if_ "take" a bool_ as first (template) argument, but behi开发者_Python百科nd the scenes "call" a if_c metafunction which expects a (const) bool as first (template) argument.
What are the arguments behind this decision?
Here is a short example, how I use these types every now and then. This example would not be possible, using const bool:
void do_something(boost::mpl::bool_<true>)
{
...
}
void do_something(boost::mpl::bool_<false>)
{
...
}
Call one of these two functions depending on the type of argument:
template<class T>
void doIt(void)
{
do_something(boost::mpl::bool_<boost::is_pointer<T>::val>())
}
In this case either the first or the second function will be called, depending on the fact if type T is a pointer or not. These types allow you to use function overloading, where it would not be possible using a const bool. With a const bool you would have to decide at runtime, which branch to take. This is specially important if called functions are themselves templates, which would not compile correctly, if they were instantiated for types other than expected, e.g. the first function definition above might contain code, which only compiles for pointers.
It's all about creating enough uniformity that the library can provide useful functionality. The MPL protocol is: "all metafunction arguments (and returns) are types." This allows us to write a templates that can operate generically on metafunctions. For example, this template accepts any metafunction (or any metafunction with up to N arguments in C++03):
template <template <class...> class some_metafunction>
struct wrapper;
Once you allow some of the template arguments to be non-types, writing such a wrapper becomes impossible. For a practical example of why we care, this uniformity allows the library to pick apart and evaluate MPL lambda expressions. If metafunction arguments were allowed to be non-types that feature would be unimplementable, because there would be no way to write out all the partial specializations needed to untangle the outer template xxx
from its arguments a
i in xxx<a1,a2,a3,...>
.
A less-interesting, if not less-valid, part of the reason is that many things become less verbose the way we did it in MPL. compare:
and_<mf0<x,y>, mf1<z>, mf2<x,z> >::value
vs
mf0<x,y>::value && mf1<z>::value && mf2<x,z>::value
I suppose one reason is that bool_<...>
are types, and when using them as results of a meta functions, you will never have to stop and think whether your result is a type and you have to do
typedef some_type result;
or a value, which has to be returned as
const static ??? result = some_value;
where you also have to keep track of the type.
Also, I suspect (I haven't worked with Boost.MPL yet) that they both have a result
type nested referring to themselves, so that you can write meta functions by just deriving from them:
template< bool b >
struct my_meta_func : bool_<b> {};
and can invoke my_meta_func::result
.
精彩评论