#include <iostream>
#include <vector>
template <typename> struct Tag {};
template <typename T>
class TemplateClass
{
public:
auto print() -> decltype(helper_print(Tag<T>{})) // SFINAE friendly
// void print() // Simple, but SFINAE unfriendly
{ return helper_print(Tag<T>{}); }
};
void helper_print(Tag<int>)
{
std::cout << "T is an int!" << std::endl;
}
void helper_print(Tag<float>)
{
std::cout << "T is a float!" << std::endl;
}
template <typename U>
void helper_print(Tag<std::vector<U>>)
{
std::cout << "T is a std::vector!" << std::endl;
}
template <typename T> class BaseOne {};
template <typename T> class BaseTwo {};
struct DerivedOne : public BaseOne<DerivedOne>
{
int i;
};
struct DerivedTwo : public BaseTwo<DerivedTwo>
{
float x, y, z;
};
// Create traits
template <template <typename> class C, typename U>
std::true_type HasTemplateBaseImpl(C<U>*);
template <template <typename> class C>
std::false_type HasTemplateBaseImpl(...);
template <typename T, template <typename> class C>
using has_template_base = decltype(HasTemplateBaseImpl<C>(std::declval<T*>()));
static_assert(has_template_base<DerivedOne, BaseOne>::value, "!");
static_assert(has_template_base<DerivedTwo, BaseTwo>::value, "!");
template <typename T,
std::enable_if_t<has_template_base<T, BaseOne>::value, bool> = false>
void helper_print(Tag<T>)
{
std::cout << "T is derived from BaseOne!" << std::endl;
}
template <typename T,
std::enable_if_t<has_template_base<T, BaseTwo>::value, bool> = false>
void helper_print(Tag<T>)
{
std::cout << "T is derived from BaseTwo!" << std::endl;
}
int main()
{
TemplateClass<int> i;
i.print();
TemplateClass<float> f;
f.print();
TemplateClass<std::vector<int>> v;
v.print();
TemplateClass<DerivedOne> d1;
d1.print();
TemplateClass<DerivedTwo> d2;
d2.print();
}