Я в ситуации, когда у меня есть цикл циклической зависимости между определениями двух классов, где (насколько я могу судить), оба класса нуждаются в том, чтобы другой тип был полным типом, чтобы правильно определить их.
В упрощенных выражениях мне нужна упрощенная версия того, что происходит:
struct Map;
struct Node {
// some interface...
private:
// this cannot be done because Map is an incomplete type
char buffer[sizeof(Map)];
// plus other stuff...
void* dummy;
};
struct Map {
// some interface...
private:
// this is Map only member
std::unordered_map<std::string, Node> map_;
};
Ситуация на самом деле более сложная, чем предыдущая, поскольку Node
на самом деле будет вариантом типа (аналогичным boost::variant
), который использует размещение new для явного построения одного из нескольких типов объектов в предварительно распределенном (и с правильным выравниванием, которое я игнорирую в этом упрощении) буфер: поэтому буфер не точно sizeof(Map)
, а скорее некоторая вычисленная константа, зависящая от sizeof(Map)
.
Проблема, очевидно, заключается в том, что sizeof(Map)
недоступен, когда Map
объявляется только вперед. Кроме того, если я сначала меняю порядок деклараций на отправку объявления Node
, тогда компиляция Map
терпит неудачу, поскольку std::unordered_map<std::string, Node>
не может быть создан, когда Node
является неполным типом, по крайней мере, с моим GCC 4.8.2 на Ubuntu. (Я знаю, что это зависит от версии libstdС++ больше, чем от версии GCC, но я не знаю, как это найти...)
В качестве альтернативы, я рассматриваю следующее обходное решение:
struct Node {
// some interface...
private:
// doing this instead of depending on sizeof(Map)
char buffer[sizeof(std::unordered_map<std::string, void*>)];
// other stuff...
void* dummy;
};
struct Map {
// some interface...
private:
// this is Map only member
std::unordered_map<std::string, Node> map_;
};
// and asserting this after the fact to make sure buffer is large enough
static_assert (sizeof(Map) <= sizeof(std::unordered_map<std::string, void*>),
"Map is unexpectedly too large");
В основном это полагается на предположение, что std::unordered_map<std::string, T>
является одним и тем же размером для всех T, что, похоже, справедливо для моего тестирования с использованием GCC.
Мой вопрос, таким образом, имеет три аспекта:
-
Есть ли что-нибудь в стандарте С++, требующем, чтобы это предположение сохранялось? (Я предполагаю, что нет, но если есть, я был бы приятно удивлен...)
-
Если нет, то практически безопасно предположить, что это верно для всех разумных реализаций, и что статическое утверждение в моей пересмотренной версии никогда не будет срабатывать?
-
Наконец, есть ли лучшее решение этой проблемы, о котором я не думал? Я уверен, что возможно что-то очевидное, что я могу сделать вместо этого, о котором я не думал, но, к сожалению, я ничего не могу придумать...