渡された型のtemplate parametersを得るメタ関数2

先日の件を経てcv修飾に対応しました。
もっと賢い実装がありそうですが、constとvolatileならせいぜい2 * 2通りしかないので凝ったことせずにそのままSFINAEで対応。

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <type_traits>
#include <boost/mpl/vector.hpp>

template<class... Types>
struct Foo;

template<class T>
struct tp_type
{
private:
    template<class>
    struct type_holder {};
    
    template<class T1, template<class...> class Type, class... Args>
    static boost::mpl::vector<const volatile Type<Args...>, Args...>
    tp_type_impl(
                 type_holder<Type<Args...>>,
                 typename std::enable_if<std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, template<class...> class Type, class... Args>
    static boost::mpl::vector<volatile Type<Args...>, Args...>
    tp_type_impl(
                 type_holder<Type<Args...>>,
                 typename std::enable_if<!std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, template<class...> class Type, class... Args>
    static boost::mpl::vector<const Type<Args...>, Args...>
    tp_type_impl(
                 type_holder<Type<Args...>>,
                 typename std::enable_if<std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<!std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, template<class...> class Type, class... Args>
    static boost::mpl::vector<Type<Args...>, Args...>
    tp_type_impl(
                 type_holder<Type<Args...>>,
                 typename std::enable_if<!std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<!std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, class Type>
    static boost::mpl::vector<const volatile Type>
    tp_type_impl(
                 type_holder<Type>,
                 typename std::enable_if<std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, class Type>
    static boost::mpl::vector<volatile Type>
    tp_type_impl(
                 type_holder<Type>,
                 typename std::enable_if<!std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, class Type>
    static boost::mpl::vector<const Type>
    tp_type_impl(
                 type_holder<Type>,
                 typename std::enable_if<std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<!std::is_volatile<T1>::value>::type* = 0
                 );
    
    template<class T1, class Type>
    static boost::mpl::vector<Type>
    tp_type_impl(
                 type_holder<Type>,
                 typename std::enable_if<!std::is_const<T1>::value>::type* = 0,
                 typename std::enable_if<!std::is_volatile<T1>::value>::type* = 0
                 );
    
public:
    using type = decltype(tp_type_impl<T>(type_holder<typename std::remove_cv<T>::type>()));
};

int main()
{
    int status;

    using type = tp_type<const int>::type;
    using test = boost::mpl::vector<const int>;
    
    std::cout << abi::__cxa_demangle(typeid(type).name(), 0, 0, &status) << std::endl;
    std::cout << abi::__cxa_demangle(typeid(test).name(), 0, 0, &status) << std::endl;
    
    std::cout << std::boolalpha << std::is_same<type, test>::value << std::endl;
    
    using type2 = tp_type<const volatile Foo<Foo<int>, double, const char>>::type;
    using test2 = boost::mpl::vector<const volatile Foo<Foo<int>, double, const char>, Foo<int>, double, const char>;

    std::cout << abi::__cxa_demangle(typeid(type2).name(), 0, 0, &status) << std::endl;
    std::cout << abi::__cxa_demangle(typeid(test2).name(), 0, 0, &status) << std::endl;
    
    std::cout << std::boolalpha << std::is_same<type2, test2>::value << std::endl;
}

出力

boost::mpl::vector<int const, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na>
boost::mpl::vector<int const, mpl
::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na>
true
boost::mpl::vector<Foo<Foo<int>, double, char const> const volatile, Foo<int>, double, char const, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na>
boost::mpl::vector<Foo<Foo<int>, double, char const> const volatile, Foo<int>, double, char const, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na, mpl::na>
true