Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ MPL or_, and_ implementations

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.

like image 800
StephQ Avatar asked Dec 24 '10 18:12

StephQ


2 Answers

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.

like image 170
Johannes Schaub - litb Avatar answered Nov 15 '22 07:11

Johannes Schaub - litb


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(); 
}
like image 32
Begemoth Avatar answered Nov 15 '22 06:11

Begemoth