В последнее время я обновлял / обновлял свои знания C ++, и изучение строгого алиасинга заставило меня немного опасаться приведения указателей одного типа к другому. Я знаю, что следующий пример кода работает на моем компиляторе на практике, но я хочу убедиться, что он соответствует действующим стандартам:
#include <iostream>
using namespace std;
class MyBase {
public:
virtual void DoSomething() = 0;
};
class MyDerived1 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #1" << endl;
}
};
class MyDerived2 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #2" << endl;
}
};
template <typename Base, typename Member1, typename Member2>
struct Tuple {
public:
Base* Get(int i) {
return &(this->*(lookupTable[i]));
}
private:
Member1 member1;
Member2 member2;
static Base Tuple::* const lookupTable[2];
};
template <typename Base, typename Member1, typename Member2>
Base Tuple<Base, Member1, Member2>::* const Tuple<Base, Member1, Member2>::lookupTable[2] = {
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member1),
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member2)
};
int main() {
Tuple<MyBase, MyDerived1, MyDerived2> tuple;
tuple.Get(0)->DoSomething();
tuple.Get(1)->DoSomething();
return 0;
}
По сути, этот простой кортеж содержит пару элементов, каждый из которых должен быть производным от общего базового класса. Функция Get возвращает Base*
члену, который представляет данный индекс.
Ключевая часть, о которой я задаюсь вопросом, это reinterpret_casts. Я знаю, что приведение от Derived Struct::*
к Base Struct::*
обычно нет-нет, но в этом случае я использую только переменную pointers-to-member для получения указателя к объекту. (Я не пытаюсь скопировать производный объект, как если бы он был базовым, и не помещать базовый объект в память производного объекта.) Это работает так, как задумано в G ++, и я просто хочу быть уверен, что я не будет укушен любыми компиляторами за это.