Background: Many functional languages support algebraic data types, which can to a degree be emulated with virtual functions and inheritance.
The most obvious solution involves a heap allocation, since the derived types come in different sizes. However, we should be able to use a union to hold even the largest type on the stack without any extra allocation. This requires an additional pointer-to-base to be stored along with the union, and at the same time complicates copying and assignment.
It's compelling to solve the latter issue by storing a member selector as an offset from the start of the union that points to the active union member. C++ has member pointers which seem almost fit for the purpose, except that the pointer to each member will have a different type.
Question: Why is it not allowed to cast Derived T::* to Base T::*?
Here's a toy example, unrelated to the above, that bumps into the same limitation:
struct fish {};
struct shark : public fish {};
struct trout : public fish {};
struct aquarium
{
shark shark;
trout trout;
};
fish aquarium::* pick_dinner(bool dangerous = true)
{
if (dangerous)
{
return &aquarium::shark;
}
return &aquarium::trout;
}
#include <iostream>
void cook(fish&)
{
std::cerr << "Do it yourself\n";
}
int main()
{
aquarium spherical, hexagonal;
fish aquarium::*ingredient = pick_dinner();
cook(spherical.*ingredient);
cook(hexagonal.*ingredient);
}
The generated compile error:
main.cpp:15:16: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'shark aquarium::*'
return &aquarium::shark;
^~~~~~~~~~~~~~~~
main.cpp:17:12: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'trout aquarium::*'
return &aquarium::trout;
^~~~~~~~~~~~~~~~
2 errors generated.