Question

I'm trying to write code that is effectively:

template <typename... Mixins>
class Checker : public Mixins... {
public:
    template<typename... Args>
    Checker(Args&&... args) : Mixins(std::forward<Args>(args))... { }

    bool check(void) {
        bool tests = true;
        // TODO: for each Mixins that has Mixin::check
        {
            tests = tests && Mixin::check();
        }

        if (!tests) {
            // TODO: for each Mixin that has Mixin::handle
            {
                Mixin::handle()
            }
        }

        return tests
    }    
};

I just don't know how to do the loops over just those Mixins satisfying the member conditions specified. I've tried various solutions for iteration and for enable_if type semantics but nothing seems to compile.

Additional

So, what I've tried so far visa vi for-each base recursion and SFINAE function elimination is the following, which doesn't compile:

template <typename C, typename... Mx>
struct do_checks;

template <typename C>
struct do_checks<C> {
    static bool check(C *) {
        return true;
    }
};


template <typename C, typename E, typename... Mx>
struct do_checks<C, E, Mx...> {
    struct general_ { };
    struct special_ : general_ { };
    template <typename> struct int_ { typedef int type; };

    template <typename F, typename int_<decltype(F::check)>::type = 0>
    static bool check(C *ptr, special_) {
        if (!ptr->F::check()) {
            return false;
        }
        return do_checks<C, Mx...>::check(ptr);
    }
    template <typename F>
    static bool check(C *ptr, general_) {
        return do_checks<C, Mx...>::check(ptr);
    }
};

Where F should be E. I don't know how to tell the compiler to compile the first "check" if the int_ has a type and the second if it doesn't.

Was it helpful?

Solution

You can create a trait named has_check which returns true for a type which has a static check() method.

namespace detail
{
    template<class T, class = decltype(T::check())>
    std::true_type has_check_impl(void*);

    template<class T>
    std::false_type has_check_impl(...);
}

template<class T>
struct has_check : decltype(detail::has_check_impl<T>(nullptr)) { };

Then you can use it as the predicate to std::enable_if to enable/disable the overload if it has the method:

private:
    template<class T, class...>
    using first = T;

    template<class T = void,
             class = 
             first<T,
                   typename std::enable_if<has_check<Mixins>::value, T>::type...>>
    static void foo(void*)
    {
        auto x{ (0, Mixins::check(), 0)... };
        (void)x;
    }

    static void foo(...)
    {
        auto x{ (0, Mixins::handle(), 0)... };
        (void)x;
    }

public:
    static void check() {
        foo(nullptr);
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top