Nested type binding in concept fails on GCC and clang but not msvc

Viewed 48

This code:

template<typename T, template<typename> typename Pred>
concept sats_pred = static_cast<bool>(Pred<T>::value);

template<template<typename...> typename A, template<typename> typename Cond>
struct is_container_of_helper {
    template<sats_pred<Cond>... Ts>
    void operator()(const A<Ts...>&) const
    {}
};

template<typename T>
struct always_true {
    static constexpr bool value = true;
};


template<typename T, template<typename...> typename Container, template<typename> typename Cond>
concept is_container_of_if = requires(const T& v, const is_container_of_helper<Container, Cond>& h)
{
    h(v);
};

template<typename T, template<typename...> typename A>
concept is = is_container_of_if<T, A, always_true>;

template<template<typename...> typename A>
struct is_a {
    template<typename T>
    struct type {
        static constexpr bool value = is<T, A>;
    };
};


template<typename T, template<typename...> typename Contained, template<typename...> typename Container>
concept is_container_of = is_container_of_if<T, Container, typename is_a<Contained>::type>;

Does not compile under gcc or clang trunk, but does under msvc (godbolt). Under gcc/clang it gives

expected a class template, got 'typename is_a<Contained>::type

Is this code valid? If not, is there a way I can achieve the same thing with valid code and why does msvc compile it?

1 Answers

Change last part of your code like this:

template<typename T, template<typename...> typename Contained, template<typename...> typename Container>
concept is_container_of = is_container_of_if<T, Container, is_a<Contained>::template type>;

And it compiles in clang and gcc. is_container_of_if needs a template for last template parameter, but you were trying to pass a type.

Related