I am trying to read the boost headers to figure out how they managed to implement the
or_<...>
and
and_<...>
metafunctions so that:
1) They can have an arbitrary number of arguments (ok, say up to 5 arguments)
2) They have short circuit behavior, for example:
or_<false_,true_,...>
does not instantiate whatever is after true_ (so it can also be declared but not defined)
Unfortunately the pre-processor metaprogramming is making my task impossible for me :P
Thank you in advance for any help/suggestion.
Here is how short circuit could work for a three-argument version
template<typename T1, typename T2, typename T2>
struct or_ : conditional<T1::value, true_, or<T2, T3>>::type
{ };
That is, if T1::value
is true, it inherits true_
, otherwise it inherits or<T2, T3>
. You need a stop criteria, which works like @begemoth shows: Specialize or_
for the first type being none_t
, which will define it's ::value
to false
.
I'm not proficient in Boost.MPL, so I can only guess how it is really implemented, but I have ideas how it could be done.
Let's begin with your first question. This have two solutions one for C++98 (with limited number of arguments) and one for C++0x.
We define or_
like this:
struct null_type { };
template<typename T1 = null_type, typename T2 = null_type, typename T3 = null_type>
struct or_
{
static const bool value = T1::value || T2::value || T3::value;
};
template<typename T1, typename T2>
struct or_<T1, T2, null_type>
{
static const bool value = T1::value || T2::value;
};
template<typename T1>
struct or_<T1, null_type, null_type>
{
static const bool value = T1::value;
};
template<>
struct or_<null_type, null_type, null_type>
{
static const bool value = false;
};
struct true_ { static const bool value = true; };
struct false_ { static const bool value = false; };
To get more parameters for the metafunction you need to specify more parameters for the or_
template. You can generate specializations using Boost.Preprocessor.
In C++0x you can use variadic templates:
template<typename... T>
struct or_;
template<>
struct or_<>
{
static const bool value = false;
};
template<typename T1, typename... Ts>
struct or_<T1, Ts...>
{
static const bool value = T1::value || or_<Ts...>::value;
};
This classic recursive list processing code. To get familiar with this style read something on functional programming.
The second question is simpler. The or_
and and_
metafunctions argument are types i.e. nullary metafunctions and they are called only when their values are needed (this is the semantics of the logical operators in C++). Using simple function the analogous code is:
bool true_() { return true; }
bool false_() { return false; }
bool or_(bool (*x)(), bool (*y)())
{
return x() || y();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With