How to Check If a Type Is an Instantiation of a Given Class Template

How can I check if a type is an instantiation of a given class template?

I came up with the following solution, using C++11 variadic templates and simple partial specialization:

#include <type_traits>

template < template <typename...> class Template, typename T >
struct is_instantiation_of : std::false_type {};

template < template <typename...> class Template, typename... Args >
struct is_instantiation_of< Template, Template<Args...> > : std::true_type {};

It could be adapted to C++03 by using the preprocessor to generate versions for a varying number of template parameters, but there is maybe a simpler way.

C++11: How to check if a type is an instantiation of a given class-template of heterogeneous NON-TYPE parameters?

You have probably hit a compiler bug. I tried to reduce this to a simpler example:

#include <iostream>

template<bool, char> struct A { };

template<typename... Ts>
struct test
{
template<typename T>
struct impl : std::false_type {};

template<Ts... Args>
struct impl<A<Args...>> : std::true_type {};
};

int main()
{
using IA = A<false, 'x'>;
std::cout << ((test<bool, char>::impl<IA>::value) ? "Y" : "N");
}

GCC 4.7.2 compiles this, but the compiled program prints the wrong output (N). On the other hand, Clang 3.2 gets this right, and the compiled program prints the correct output (Y).

Here is a slightly modified version of the above program, where the test class template much resembling your is_instantiation_of__nontypes_v2__ class template:

#include <iostream>

template<bool, char> struct A {};

template<typename... Ts>
struct test
{
template<template<Ts...> class TT, typename T>
struct impl : std::false_type {};

template<template<Ts...> class TT, Ts... Args>
struct impl<TT, TT<Args...>> : std::true_type {};
};

int main()
{
using IA = A<false, 'x'>;
std::cout << ((test<bool, char>::impl<A, IA>::value) ? "Y" : "N");
}

While Clang compiles this and the compiled program prints the correct output (Y), GCC emits the following compilation error:

expected a template of type 'template<class ... Ts> template<Ts ...<anonymous> > class TT', got 'template<bool <anonymous>, char <anonymous> > struct A'.

It looks like GCC does not recognize that the first template template parameter should have a template argument list given by the expansion of Ts. Therefore, it seems to me this is a bug of GCC.

How to tell if template type is an instance of a template class?

Here's an option:

#include <iostream>
#include <type_traits>
#include <string>

template <class, template <class> class>
struct is_instance : public std::false_type {};

template <class T, template <class> class U>
struct is_instance<U<T>, U> : public std::true_type {};

template <class>
class Second
{};

int main()
{
using A = Second<int>;
using B = Second<std::string>;
using C = float;
std::cout << is_instance<A, Second>{} << '\n'; // prints 1
std::cout << is_instance<B, Second>{} << '\n'; // prints 1
std::cout << is_instance<C, Second>{} << '\n'; // prints 0
}

It's basically specializing the is_instance struct for types that are instantiations of a template.

Is it possible to check if a type has been instantiated with a specific template parameter?

Not sure to understand what do you exactly want... but I suppose is something as

template <class check, template<class...> class TypeToCheck, class... T>
constexpr bool does_obj_contain_type(TypeToCheck<T...>) {
return (std::is_same_v<check, T> || ...);
}

// ...

using T = Empty<int, double>;

auto x = does_obj_contain_type<double>(T{});

But it's a problem if you can't instantiate an object of type T. In the case, I suppose you can use class/struct specialization.

Something as

template <typename>
struct does_obj_contain_type;

template <template <typename...> class TTC, typename ... Ts>
struct does_obj_contain_type<TTC<Ts...>>
{
template <typename check>
static constexpr bool func ()
{ return (std::is_same_v<check, Ts> || ...); }
};

// ...

using T = Empty<int, double>;

constexpr auto x = does_obj_contain_type<T>::func<double>();

Or maybe better as a template variable value (suggested by super: thanks!)

template <template <typename...> class TTC, typename ... Ts>
struct does_obj_contain_type<TTC<Ts...>>
{
template <typename Check>
static constexpr auto value = (std::is_same_v<Check, Ts> || ...);
};

// ...

using T = Empty<int, double>;

constexpr auto x = does_obj_contain_type<T>::value<double>;

How to check if a type is instantiated from a certain variadic template class in a template function?

You can create a trait to test for instantiations of Foo, and then fold it across all your parameters.

template <typename>
struct is_foo : std::false_type {};

template <typename... Ts>
struct is_foo<Foo<Ts...>> : std::true_type {};

template <typename T>
constexpr bool is_foo_v = is_foo<T>::value;

template <typename... T>
void Bar(const T&... arguments) {
static_assert((is_foo_v<T> && ...), "arguments must all be Foos");
}

See it on coliru

Detect the existence of a template instantiation for a given type

Here's a link-time solution. Works on GCC, Clang, and MSVC.

One template (impl::Checker<T>) declares a friend function and calls it.

Another template (impl::Marker) defines that function. If it's not defined, the first class gets an undefined reference.

run on gcc.godbolt.org

#include <cstddef>
#include <type_traits>

namespace impl
{
template <typename T>
struct Checker
{
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
friend void adl_MarkerFunc(Checker<T>);
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif

static std::nullptr_t Check()
{
adl_MarkerFunc(Checker<T>{});
return nullptr;
}

inline static const std::nullptr_t check_var = Check();
static constexpr std::integral_constant<decltype(&check_var), &check_var> use_check_var{};
};

template <typename T>
struct Marker
{
friend void adl_MarkerFunc(Checker<T>) {}
};
}

template <typename T, impl::Checker<T> = impl::Checker<T>{}>
struct Access
{
template <typename U>
void Read()
{
static_assert(std::is_same_v<T, U>);
(void)impl::Marker<U>{};
}
};

int main()
{
Access<int> x;
x.Read<int>();

[[maybe_unused]] Access<float> y; // undefined reference to `impl::adl_MarkerFunc(impl::Checker<float>)'

using T [[maybe_unused]] = Access<double>; // undefined reference to `impl::adl_MarkerFunc(impl::Checker<double>)'
}

Had to introduce a dummy template parameter to Access, since I couldn't think of any other way of detecting it being used in a using.

How to check if an object is an instance of a template class in C++?

This is pretty straightforward using a specialized helper class:

#include <type_traits>
#include <iostream>

template<typename T> class A {};

template<typename T>
struct is_a : std::false_type {};

template<typename T>
struct is_a<A<T>> : std::true_type {};

int main()
{
auto a1=A<int>{};

bool b1=false;

std::cout << is_a<decltype(a1)>::value << std::endl;

std::cout << is_a<decltype(b1)>::value << std::endl;
return 0;
}

is_a gets specialized for a template parameter that's any instance of A. The non-specialized version is the false trait, and the specialized version is the true trait, and that's pretty much it. If you are not familiar with the topic of template specialization, this is a fairly involved and deep topic that should have a full explanation in every good C++ textbook, and I refer you there for a full and complete discussion on this topic.

C++ Concepts: checking for template instantiation

Using C++17 class template argument deduction, you should be able to do something like this:

template<typename A, typename B, typename C>
struct mytype { };

template<class T>
concept C1 = requires(T x) {
{ mytype{x} } -> std::same_as<T>;
};

mytype{x} uses class template argument deduction to deduce A, B and C, so this is valid if you can construct a mytype<A, B, C> from a T. In particular, this is valid if mytype is copy-constructible since you have an implicitly declared copy-deduction guide similar to:

template <typename A, typename B, typename C>
mytype(mytype<A, B, C>) -> mytype<A, B, C>;

Checking that T is also the constructed mytype instantiation avoid matching other deduction guides, e.g., this would match for any type without the -> std::same_as<T>:

template <class A, class B, class C>
struct mytype {
mytype(A);
};

template <class A>
mytype(A) -> mytype<A, A, A>;

The proposed solution does not work for non copy-constructible classes, even though should be possible to make it work for move-only classes.


Tested with clang and gcc: https://godbolt.org/z/ojdcrYqKv

How to check if an object is an instance of template class of multiple template arguments and that one of said arguments fulfills some condition?

You were on the right track:

#include <type_traits>
#include <iostream>

template <typename T1, typename T2>
struct A
{
};

template <typename Type, typename=void>
struct IsA: std::false_type
{
};

template <typename T1, typename T2>
struct IsA<A<T1, T2>, std::enable_if_t<std::is_same_v<T2, int>>>
: std::true_type
{
};

int main()
{
std::cout << IsA<int>::value << "\n";

std::cout << IsA<A<char, char>>::value << "\n";

std::cout << IsA<A<char, int>>::value << "\n";
return 0;
}

In this trivial example the "some condition" is just a std::is_same_v<T2, int>, only for the sake of an example.



Related Topics



Leave a reply



Submit