Search code examples
c++type-traitsboost-mpl

Using boost::mpl::find_if with custom predicate


Given

struct A {};
struct B {};
struct C {C(B) {}};
struct D : B {};
struct E {operator A() const {return A();}};
struct F {};

using AllowedTypes = boost::mpl::vector<A, C>;

I'm trying to implement a predicate is_allowed_type so that

static_assert(is_allowed_type<A>::value, "A is in AllowedTypes");
static_assert(is_allowed_type<B>::value, "C is constructible from B");
static_assert(is_allowed_type<C>::value, "C is in AllowedTypes");
static_assert(is_allowed_type<D>::value, "D inherits from B, from which C is constructible");
static_assert(is_allowed_type<E>::value, "E is convertible to A");
static_assert(!is_allowed_type<F>::value, "F is not convertible to A nor C");

The predicate must return true iff its argument is convertible to one of the types in AllowedTypes.

Here is what I have come up with.

template <typename T>
struct is_allowed_type
{
    using I = boost::mpl::find_if<AllowedTypes, std::is_convertible<T, boost::mpl::_>>;
    using End = boost::mpl::end<AllowedTypes>;
    enum {value = !std::is_same<I, End>::value};
};

The last assertion fails. What is wrong with my is_allowed_type?


Solution

  • I found the answer while writing the question but since I had difficulties to find material on the subject I am posting it.

    The iterator definitions in is_allowed_type are missing ::type. The correct implementation is

    template <typename T>
    struct is_allowed_type
    {
        using I = typename boost::mpl::find_if<AllowedTypes, std::is_convertible<T, boost::mpl::_>>::type;
        using End = typename boost::mpl::end<AllowedTypes>::type;
        enum {value = !std::is_same<I, End>::value};
    };