For base classes:
#include <type_traits>
template<bool b>
using stdbool_t = std::integral_constant<bool, b>;
template<class T, class U = std::true_type>
struct trait
: std::false_type
{};
struct foo {};
struct bar : foo {};
template<class T>
struct trait<T, stdbool_t<std::is_base_of<foo, T>{}>>
: std::true_type
{};
#include <iostream>
int main()
{
std::cout << std::boolalpha;
std::cout << trait<int>::value << "\n";
std::cout << trait<foo>::value << "\n";
std::cout << trait<bar>::value << "\n";
}
For some reason, specializing on non-type template parameters isn't allowed when the expression depends on (the previous) type parameters.
g++4.8.2 fails to compile this btw (ICE), but it works fine with clang++3.5
Here's an alternative version that compiles on both compilers:
template<class T, class = void>
struct trait
: std::false_type
{};
struct foo {};
struct bar : foo {};
template<class T>
struct trait<T, typename std::enable_if<std::is_base_of<foo, T>{}>::type>
: std::true_type
{};
The enable_if
isn't necessary, actually. A std::conditional
would work as well, but the enable_if
is shorter here.
If the base is a template specialization, we can use Jarod42's solution (I've modified it a bit):
template<template<class...> class T, class U>
struct is_base_template_of
{
private:
template<class... V>
static auto test(const T<V...>&)
-> decltype(static_cast<const T<V...>&>(std::declval<U>()),
std::true_type{});
static std::false_type test(...);
public:
static constexpr bool value =
decltype(is_base_template_of::test(std::declval<U>()))::value;
};
template<class T>
struct trait<T,
typename std::enable_if<is_base_template_of<foo, T>::value>::type>
: std::true_type
{};
Note: this only works for public inheritance (and I think it has some further restrictions: virtual and some cases of multiple inheritance shouldn't work either).
Here's a version of the same type trait in "C++03 + boost" style:
template<template<class> class T, class U>
struct is_base_template_of
{
private:
typedef char false_type;
typedef char(& true_type)[2];
template<class V>
static true_type test(const T<V>*);
static false_type test(...);
public:
static const bool value =
( sizeof(test(std::declval<typename std::remove_reference<U>::type*>()))
== sizeof(true_type));
};