Search code examples
c++boostboost-mp11

Struggling with Boost.Mp11: "expected a class template, got 'T'"


I am trying to check the unspecialised uniqueness of a tuple of specialised types using Boost.Mp11:

#include <iostream>
#include <vector>
#include <deque>
#include <tuple>

#include <boost/mp11/algorithm.hpp>

namespace
{
template <typename T, template <typename...> typename U>
struct is_specialisation : std::false_type {};

template <template <typename...> typename U, typename... Args>
struct is_specialisation<U<Args...>, U> : std::true_type {};

template <template <typename...> typename U>
struct is_specialisation_meta
{
    template <typename T>
    using type = is_specialisation<T, U>;
};

template <typename TypeList>
struct unique_specialisation
{
    template <typename T>
    using type = std::is_same<
        boost::mp11::mp_count_if<
            TypeList,
            is_specialisation_meta<T>::template type // Error!
        >,
        boost::mp11::mp_size_t<1>
    >;
};
}

int main()
{
    using types = std::tuple<
        std::vector<int>,
        std::deque<int>,
        std::tuple<int>
    >;

    using all_unique_specialisations = boost::mp11::mp_all_of<
        types,
        unique_specialisation<types>::template type
    >;

    std::cout << std::boolalpha << all_unique_specialisations::value << std::endl;

    return EXIT_SUCCESS;
}

You can run the above code on Coliru. For each type, the whole list is iterated over trying to find an unspecialised equivalent, so {std::vector<int>, std::deque<float>, std::tuple<Foo>} would pass but {std::vector<int>, std::vector<float>, std::tuple<Foo>} would not.

However I get this error:

main.cpp:30:37: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class ...> class U> struct {anonymous}::is_specialisation_meta'
             is_specialisation_meta<T>::template type
                                     ^
main.cpp:30:37: note:   expected a class template, got 'T'

But I don't understand how T is unknown - can anyone see what I am doing wrong?


Solution

  • The immediate error is in...

    template <typename T>
    using type = std::is_same<
        boost::mp11::mp_count_if<
            TypeList,
            is_specialisation_meta<T>::template type // Error!
        >,
        boost::mp11::mp_size_t<1>
    >;
    

    If we compare it against...

    template <template <typename...> typename U>
    struct is_specialisation_meta
    

    ... we see that the code passes a typename T where a template U is expected. But amending that only shifts the error elsewhere, because now boost.mp is not going to get the predicate type it expects. I'm afraid I'm not too familiar with the library to tell you how to get a working version beyond this.