Я нашел решение из другого вопроса , который позволяет мне работать во время компиляции, если тип является полиморфным, и затем я могу использовать его со специализацией шаблона для использования правильного типа приведения. Очевидно, этот метод может сломаться, если компилятор добавляет заполнение между подобъектами, но я надеюсь, что я добавлю некоторые утверждения времени компиляции в некоторых известных случаях, чтобы поймать это. Он правильно компилируется и работает как на MSVC, так и на GCC.
Это код для работы, если тип полиморфный.
#define SIMPLE_POLYMORPHIC(TYPE, POLYMORPHIC) \
template <> \
struct IsPolymorphic<TYPE> \
{ \
static const bool value = POLYMORPHIC; \
};
template <typename T>
struct IsPolymorphic
{
struct Derived : public T { virtual ~Derived(); };
static const bool value = (sizeof(Derived) == sizeof(T));
};
SIMPLE_POLYMORPHIC(int, false);
SIMPLE_POLYMORPHIC(unsigned int, false);
// ... do this for all intrinsic or non-derivable types
Код для выполнения приведения в зависимости от того, является ли тип полиморфным.
template <typename T, bool isPolymorphic = IsPolymorphic<T>::value>
struct StartOfObject
{
static void* getStart(T *const ptr)
{
return static_cast<void*>(ptr);
}
};
template <typename T>
struct StartOfObject<T, true>
{
static void* getStart(T *const ptr)
{
if(ptr)
return dynamic_cast<void*>(ptr);
return NULL;
}
};
И контрольный пример для него.
#define CLASS_STUFF(CLASS) \
public: \
CLASS() {} \
virtual ~CLASS() {} \
int m_##CLASS;
class A
{
CLASS_STUFF(A);
};
class B : public A
{
CLASS_STUFF(B);
};
class C
{
};
#include <iostream>
int main()
{
std::cout << IsPolymorphic<A>::value << std::endl;
std::cout << IsPolymorphic<B>::value << std::endl;
std::cout << IsPolymorphic<C>::value << std::endl;
std::cout << IsPolymorphic<int>::value << std::endl;
StartOfObject<A>::getStart(new A());
StartOfObject<B>::getStart(new B());
StartOfObject<C>::getStart(new C());
StartOfObject<int>::getStart(new int());
return 0;
};