/ / Як слід передавати двійкові предикати в користувацький алгоритм Boost.MPL? - c ++, boost-mpl, шаблон-мета-програмування

Як бінарні предикати повинні передаватися користувальницькому алгоритму Boost.MPL? - C ++, boost-mpl, шаблон-мета-програмування

Розглянемо наступну спробу версії метапрограмування в стилі Boost.MPL 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;
}

Тут друкується: 1 1 1 1 1 1 1 1 0. Тобто, останній дзвінок до all_of з std::is_base_of переданий як предикат генерує false. Чому це не працює? Очевидно, базовий клас B не прив’язується належним чином до присудка. Як мені передати двійковий предикат? Якась комбінація mpl :: lambda або mpl :: bind?

UPDATE

На основі чудової відповіді Люка Туреля, ось без лямбда-розв’язання моє запитання, з додатковим бонусом версії під час компіляції none_of і 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 > >
{};

Відповіді:

1 для відповіді № 1

Ось рішення, що використовує find_if замість 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
>
{};

Якщо ти хочеш дотримуватися fold, вам потрібно буде перетворити предикат на метафункцію за допомогою lambda перед тим як викликати його, до захистити аргументи:

boost::mpl::apply< typename
boost::mpl::lambda< Pred >::type,
boost::mpl::_2
>

Однак ви зауважите, що і це не спрацює. Я не впевнений, чому саме, я думаю, це пов'язано з це обговорення у списку розсилки Boost. Судячи з усього, є проблема із суттю apply що більше, ніж підтримуваний lambda. У будь-якому випадку, простий обхідний шлях полягає у використанні apply1 замість apply. Ось повне рішення:

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
>
>
>
{};

1 для відповіді № 2

Вам потрібно перетворити предикат на лямбду, або _1 буде інтерпретовано як перший рівень викликів згину, а не перший параметр, який буде передано Pred. mpl :: lambda - це те, що вам потрібно