При определении типов классов вы можете использовать тот факт, что указатели на элементы существуют
template<typename A, typename B>
struct issame { };
template<typename A>
struct issame<A, A> { typedef void type; };
template<typename> struct tovoid { typedef void type; };
template<typename T, typename = void>
struct isclass { static bool const value = false; };
template<typename C>
struct isclass<C, typename tovoid<int C::*>::type> {
static bool const value = true;
};
Вы не можете обнаружить разницу между объединенным и не объединенным классом. По крайней мере, я не знаю как, и повышение не знает также.
Я думаю, что обнаружение перечислений может сработать, убедившись, что T
не является классом, функцией или целочисленным типом, и затем попытайтесь присвоить целочисленный тип. Вы могли бы
template<typename E, typename = void>
struct isenum {
struct No { char x; };
struct Yes { No n1; No n2; };
struct nullsink {};
static No checkI(nullsink*); // accept null pointer constants
static Yes checkI(...);
static Yes checkE(int);
static No checkE(...);
static bool const value = (sizeof(checkI(E())) == sizeof(Yes)) &&
(sizeof(checkE(E())) == sizeof(Yes));
};
// class
template<typename E>
struct isenum<E, typename tovoid<int E::*>::type> {
static bool const value = false;
};
// reference
template<typename R>
struct isenum<R&, void> {
static bool const value = false;
};
// function (FuntionType() will error out).
template<typename F>
struct isenum<F, typename issame<void(F), void(F*)>::type> {
static bool const value = false;
};
// array (ArrayType() will error out)
template<typename E>
struct isenum<E[], void> {
static bool const value = false;
};
template<typename E, int N>
struct isenum<E[N], void> {
static bool const value = false;
};
Быстрый и грязный тест (работает на GCC / Clang / Comeau):
enum A { };
struct B { };
typedef int &C;
typedef void D();
typedef int E;
typedef long F;
typedef int const G;
typedef int H[1];
template<typename T, bool E>
struct confirm { typedef char x[(T::value == E) ? 1 : -1]; };
int main() {
confirm< isenum<A>, true >();
confirm< isenum<B>, false >();
confirm< isenum<C>, false >();
confirm< isenum<D>, false >();
confirm< isenum<E>, false >();
confirm< isenum<F>, false >();
confirm< isenum<G>, false >();
confirm< isenum<H>, false >();
}