Consider the following attempt at a Boost.MPL style metaprogramming version of std::any_of
#include <iostream> // cout
#include <type_traits> // is_base_of, is_pod
#include <boost/mpl/apply.hpp> // apply
#include <boost/mpl/fold.hpp> // fold
#include <boost/mpl/lambda.hpp> // lambda, _1, _2
#include <boost/mpl/logical.hpp> // and_, true_
#include <boost/mpl/vector.hpp> // vector
template
<
typename Sequence,
typename Pred
>
struct all_of
:
boost::mpl::fold<
Sequence,
boost::mpl::true_,
boost::mpl::lambda<
boost::mpl::and_<
boost::mpl::_1,
boost::mpl::apply< Pred, boost::mpl::_2 >
>
>
>
{};
typedef int P1; typedef char P2; typedef float P3;
typedef boost::mpl::vector<
P1, P2, P3
> pod_types;
struct B {}; struct D1: B {}; struct D2: B {}; struct D3: B {};
typedef boost::mpl::vector<
D1, D2, D3
> derived_types;
int main()
{
std::cout << (std::is_pod<P1>::value) << '\n'; // true
std::cout << (std::is_pod<P2>::value) << '\n'; // true
std::cout << (std::is_pod<P3>::value) << '\n'; // true
std::cout << (
all_of<
pod_types,
std::is_pod< boost::mpl::_1 >
>::type::value // true
) << '\n';
std::cout << (std::is_base_of<B, D1>::value) << '\n'; // true
std::cout << (std::is_base_of<B, D2>::value) << '\n'; // true
std::cout << (std::is_base_of<B, D3>::value) << '\n'; // true
std::cout << (
all_of<
derived_types,
std::is_base_of< B, boost::mpl::_1 >
>::type::value // false (but should be true)
) << '\n';
return 0;
}
This prints out: 1 1 1 1 1 1 1 0. I.e., the final call to all_of
with std::is_base_of
passed as a predicate generates false. Why does this not work? Apperently, the base class B
does not get properly bound to the predicate. How should I pass a binary predicate? Some combination of mpl::lambda or mpl::bind?
UPDATE
Based on Luc Touraille's excellent answer, here is the lambda-free solution to my question, with as an added bonus the compile-time versions of none_of
and any_of
template<typename Sequence, typename Pred>
struct all_of
:
std::is_same< typename
boost::mpl::find_if<
Sequence,
boost::mpl::not_<Pred>
>::type, typename
boost::mpl::end<Sequence>::type
>
{};
template<typename Sequence, typename Pred>
struct none_of
:
all_of< Sequence, boost::mpl::not_< Pred > >
{};
template<typename Sequence, typename Pred>
struct any_of
:
boost::mpl::not_< none_of< Sequence, Pred > >
{};
Here is a solution using find_if
instead of fold
:
#include <type_traits>
#include <boost/mpl/end.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/logical.hpp>
template
<
typename Sequence,
typename Pred
>
struct all_of
:
std::is_same< typename
boost::mpl::end< Sequence >::type, typename
boost::mpl::find_if<
Sequence,
boost::mpl::not_< Pred >
>::type
>
{};
If you want to stick to fold
, you'll need to turn the predicate into a metafunction using lambda
before invoking it, to protect the arguments:
boost::mpl::apply< typename
boost::mpl::lambda< Pred >::type,
boost::mpl::_2
>
However, you'll note that this won't work either. I'm not sure why exactly, I think it is related to this discussion on the Boost mailing list. Apparently, there is an issue with the arity of apply
which is greater than the one supported by lambda
. Anyway, a simple workaround is to use apply1
instead of apply
. Here is the full solution:
template
<
typename Sequence,
typename Pred
>
struct all_of
: boost::mpl::fold<
Sequence,
boost::mpl::true_,
boost::mpl::and_<
boost::mpl::_1,
boost::mpl::apply1< typename
boost::mpl::lambda< Pred >::type,
boost::mpl::_2
>
>
>
{};