Почему нельзя приводить Derived T :: * к Base T :: *?

Фон: Многие функциональные языки поддерживают алгебраические типы данных, которые в некоторой степени можно эмулировать с помощью виртуальных функций и наследования.

Наиболее очевидное решение заключается в распределении кучи, поскольку производные типы
различные размеры. Однако мы должны иметь возможность использовать объединение для хранения даже самого большого типа в стеке без какого-либо дополнительного выделения. Это требует сохранения дополнительного указателя на базу вместе с объединением, и в то же время усложняет копирование и назначение.

Это решает последнюю проблему, сохраняя селектор члена как смещение от начала объединения, которое указывает на активного члена объединения. В C ++ есть указатели на члены, которые кажутся почти подходящими для этой цели, за исключением того, что указатель на каждый член будет иметь другой тип.

Вопрос: Почему нельзя приводить Derived T :: * к Base T :: *?

Вот игрушечный пример, не связанный с вышеизложенным, который сталкивается с тем же ограничением:

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);
}

Сгенерированная ошибка компиляции:

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.

2

Решение

Почему не разрешено разыгрывать Derived T::* в Base T::*?

Потому что это не разрешено языковым стандартом. Единственный указатель на преобразование члена, который разрешен, кроме преобразования нулевого указателя на член, это преобразование типа cv T Base::* в cv T Derived::*, как указано в Стандартной части 4.11/2,

Я не знаю точную причину этого, но соответствующий Основная языковая проблема 794 было отвергнуто из-за «нет единого мнения, чтобы сделать это изменение на данном этапе процесса стандартизации». Недавняя активность Эта проблема указывает на то, что она может измениться в следующем стандарте C ++ (C ++ 17).

4

Другие решения


По вопросам рекламы [email protected]