I need some code to check whether a certain template is part of a parameter pack. To implement the check for normal classes, I use the multiple-inheritance based approach outlined e.g. by Louis Dionne here or Agustín Bergé here.
Testing for a Class
The idea is that you wrap every class T
in the pack in an PackEntry
class, and then have PackIndex
inherit from all PackEntry
classes. This way, if you are looking for a class A
, all you need to do is check if a PackIndex
can be converted to the correct PackEntry
. Throwing everything together, it looks like this:
#include <cstddef>
#include <utility>
template <class T>
struct PackEntry
{
using type = T;
};
template <class... Ts>
struct PackIndex : PackEntry<Ts>...
{};
template <class T, class... Ts>
struct PackSearcher
{
static constexpr std::false_type check(...);
// This overload is used if the PackIndex below
// derives from PackEntry<T>, the overload above
// otherwise.
static constexpr std::true_type check(PackEntry<T>);
using type =
decltype(check(PackIndex<Ts...>{}));
static constexpr bool
value()
{
return type{};
}
};
template <class... Ts>
struct Pack
{
template<class T>
static constexpr bool has() {
return PackSearcher<T, Ts...>::value();
}
};
int main() {
static_assert(Pack<int, void>::has<int>());
static_assert(! Pack<int, void>::has<bool>());
}
Testing for a Specific Template
Now, this is all neat, but say that I have a template Tmpl
, and I want to know whether my pack contains any specialization of that template. I's easy to do if the template has a specific form, say template <std::size_t> class Tmpl {};
Basically, the only difference is that inside the PackSearcher
(which I now call TmplPackSearcher
, you make the compiler derive the correct N
template parameter for the template.
#include <cstddef>
#include <utility>
template <class T>
struct PackEntry
{
using type = T;
};
template <class... Ts>
struct PackIndex : PackEntry<Ts>...
{
};
template <template <std::size_t> class T, class... Ts>
struct TmplPackSearcher
{
static constexpr std::false_type check(...);
template <std::size_t N>
static constexpr std::true_type check(PackEntry<T<N>>);
using type =
decltype(check(PackIndex<Ts...>{}));
static constexpr bool
value()
{
return type{};
}
};
template <class... Ts>
struct Pack
{
template<template <std::size_t> class T>
static constexpr bool has_tmpl() {
return TmplPackSearcher<T, Ts...>::value();
}
};
template<std::size_t I>
class Tmpl {};
int main() {
static_assert(Pack<Tmpl<1>, int>::has_tmpl<Tmpl>());
static_assert(!Pack<int>::has_tmpl<Tmpl>());
}
The Question
Now, my question is: How do I test for the presence of a template in a parameter pack without making any assumption how the template looks like? I.e., I don't want to write separate code for template<std::size_t>
, template<std::size_t, typename>
, template <typename, typename>
, etc.
Bonus points if it can be done using the same multiple-inheritance trick.