5

Using Check if class is a template specialization?, I can check if a class is a specialization of a template.

Using std::is_convertible<A*, B*>, I can check whether A is a child class of B.

How can I implement is_convertible_specialization, something that would do:

template<typename ... Args> 
class Base {};

template<typename ... Args> 
class Child : public Base<Args...> {};

template<typename ... Args>
class Unrelated{};

static_assert( is_convertible_specialization<Child<int, int>, Base>{} ); // True
static_assert( is_convertible_specialization<Unrelated<int, int>, Base>{} ); // False

I've tried a few things already, but my skills in TMP are rather lacking, so I don't think I've come close. My "best" attempt is:

template<template<class...> class ChildTemplate, template<class...> class Template, class... Args>
struct is_convertible_specialization : std::false_type {};

template<template<class...> class ChildTemplate, template<class...> class Template, class... Args>
struct is_convertible_specialization<ChildTemplate<Args...>, Template> : std::true_type {
    is_convertible_specialization() {
        static_assert( std::is_convertible<ChildTemplate<Args...> *, Template<Args...> *>());
    }
};

in which I attempt to "nest" assertions in a way that seemed simple to me. This provides me with the following error message, which seems vaguely sensible, but not really comprehensible for me.

Template argument for template template parameter must be a class template or type alias template

Kjeld Schmidt
  • 771
  • 8
  • 19

1 Answers1

5

You were close.

First, the template parameters of the primary template (but not the specialization) must match the way you want to use your template:

template <typename ChildTemplate, template<class...> class Template>

Next, if the pointers are not convertible, the specialization of is_convertible_specialization should evaluate to false instead of triggering a static assertion. You can do that by inheriting from std::is_convertible_v<...> instead of std::true_type, and removing the custom constructor.

Here's the result:

template <typename ChildTemplate, template<class...> class Template>
struct is_convertible_specialization : std::false_type {};

template <template<class...> class ChildTemplate, template<class...> class Template, class... Args>
struct is_convertible_specialization<ChildTemplate<Args...>, Template>
    : std::is_convertible<ChildTemplate<Args...> *, Template<Args...> *>
{};
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207