Created
November 30, 2018 10:47
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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!"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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!