Skip to content

Instantly share code, notes, and snippets.

@bad-ed
Created November 30, 2018 10:47
Show Gist options
  • Select an option

  • Save bad-ed/72d7d1310b988ffd8ea6dc2bd21ffcda to your computer and use it in GitHub Desktop.

Select an option

Save bad-ed/72d7d1310b988ffd8ea6dc2bd21ffcda to your computer and use it in GitHub Desktop.
C++ traits for templates with type arguments (is_template, is_instance_of_template, is_derived_of_template)
#include <type_traits>
// Determine if `Instance` is instantiation of template
// e.g. static_assert(is_template<std::vector<int>>::value);
template<class Instance> struct is_template : std::false_type {};
template<class ...TemplateArgs, template<class...> class Template>
struct is_template<Template<TemplateArgs...>> : std::true_type {};
// Determine if `Instance` is instance of `Template`
// e.g. static_assert(is_instance_of_template<std::vector, std::vector<int>>::value);
template<template<class...> class Template, class Instance>
struct is_instance_of_template : std::false_type {};
template<class ...TemplateArgs, template<class...> class Template>
struct is_instance_of_template<Template, Template<TemplateArgs...> > : std::true_type {};
// Determine if class inherits specified template
namespace detail {
template<template<class...> class Template, class ...TemplateArgs>
std::true_type is_base_checker(const volatile Template<TemplateArgs...>*);
template<template<class...> class>
std::false_type is_base_checker(const volatile void*);
// Additional checker is needed to avoid hard compilation error in case of private inheritance
template<template<class...> class Template, class Instance, class = void>
struct is_base_checker_helper : std::true_type {};
template<template<class...> class Template, class Instance>
struct is_base_checker_helper<Template, Instance,
std::void_t<decltype(is_base_checker<Template>(std::declval<Instance*>()))>
> : decltype(is_base_checker<Template>(std::declval<Instance*>())) {};
} // namespace detail
template<template<class...> class Template, class Instance>
struct is_derived_of_template : detail::is_base_checker_helper<Template, Instance> {};
// Tests
template<class ...Args>
struct TestableTemplate {};
template<class ...Args>
struct TestableTemplate2 {};
struct Struct {};
struct DerivedStruct : TestableTemplate<int, double> {};
class PrivateDerivedStruct : TestableTemplate<int, double> {};
struct MultipleInheritance : TestableTemplate<int, double>, TestableTemplate<char> {};
static_assert(is_template<TestableTemplate<int, char>>::value, "WTF!");
static_assert(is_template<Struct>::value == false, "WTF!");
static_assert(is_instance_of_template<TestableTemplate, TestableTemplate<int, char>>::value, "WTF!");
static_assert(is_instance_of_template<TestableTemplate2, TestableTemplate<int, char>>::value == false, "WTF!");
static_assert(is_instance_of_template<TestableTemplate, Struct>::value == false, "WTF!");
static_assert(is_derived_of_template<TestableTemplate, DerivedStruct>::value, "WTF!");
static_assert(is_derived_of_template<TestableTemplate, PrivateDerivedStruct>::value, "WTF!");
static_assert(is_derived_of_template<TestableTemplate, MultipleInheritance>::value == false, "WTF!"); // FAILS On VS 15.7
static_assert(is_derived_of_template<TestableTemplate, Struct>::value == false, "WTF!");
static_assert(is_derived_of_template<TestableTemplate, TestableTemplate<int, char>>::value, "WTF!");
@dbecker59
Copy link
Copy Markdown

This is awesome! This is exactly what I needed. I'm using it to detect if a template parameter is a std::complex instance. Good work mate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment