I am trying to trade some run-time checks for compile-time checks to identify the base class of an object with template specializations.
The code compiles fine, but I can't figure out why the enable_if
statement always end up invalid or equal to void
because I'm always landing on the base template struct.
#include <iostream>
#include <type_traits>
using namespace std;
struct BaseOne {};
struct DerivedOne : BaseOne {};
struct BaseTwo {};
struct DerivedTwo : BaseTwo {};
struct Default {};
template<typename T, typename = void>
struct get_category_impl {
static constexpr int value = 0;
};
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseOne, T>::value, T>::type> {
static constexpr int value = 1;
};
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseTwo, T>::value, T>::type> {
static constexpr int value = 2;
};
template<typename T>
constexpr int get_category = get_category_impl<T>::value;
int main() {
cout << get_category<BaseOne> << "\n"; // prints 0
cout << get_category<DerivedOne> << "\n"; // prints 0
cout << get_category<BaseTwo> << "\n"; // prints 0
cout << get_category<DerivedTwo> << "\n"; // prints 0
cout << get_category<Default> << "\n"; // prints 0
}
The second parameter to enable_if
doesn't need to be specified. If you do specify it, it needs to somehow resolve to void
. Since you've specified the second parameter as T
, this doesn't work.
Instead, just do this:
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseOne, T>::value>::type> {
// ^ No T
static constexpr int value = 1;
};
and similarly for the other specialization.
Here's a demo.