Получение & quot; родительского & quot; `std :: tuple` от & quot; детей & quot; указатели предметов

struct Apple { };
struct Banana { };
struct Peach { };

using FruitTuple = std::tuple<Apple, Banana, Peach>;

template<typename TTuple, typename TItem>
TTuple& getParentTuple(TItem* mItemPtr)
{
// <static assert that the tuple item types are unique>
// ...?
}

int main()
{
FruitTuple ft;

// I know these pointers point to objects inside a `FruitTuple`...
Apple* ptrApple{&std::get<0>(ft)};
Banana* ptrBanana{&std::get<1>(ft)};
Peach* ptrPeach{&std::get<2>(ft)};

// ...is there a way to get the `FruitTuple` they belong to?
auto& ftFromA(getParentTuple<FruitTuple>(ptrApple));
auto& ftFromB(getParentTuple<FruitTuple>(ptrBanana));
auto& ftFromP(getParentTuple<FruitTuple>(ptrPeach));

assert(&ftFromA == &ftFromB);
assert(&ftFromB == &ftFromP);
assert(&ftFromA == &ftFromP);

return 0;
}

Как может getParentTuple<TTuple, TItem> быть реализован в Стандарт-совместимый а также не-зависит от архитектуры путь?

2

Решение

Невозможно.

Редактировать:

Я не думаю, что в стандарте есть что-то, что мешает реализации кортежей, отвечающих требованиям, распределять элементы по отдельности в куче.

Расположение в памяти элементов, таким образом, не допускает никаких выводов, которые приводят к расположению объекта кортежа.

Единственное, что вы можете сделать, это расширить ваши классы элементов, чтобы они также содержали обратный указатель на кортеж, который вы затем заполняете после помещения ваших элементов в кортеж.

3

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

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

В комментарии вы сказали, что вас не волнует этот случай, так что вот и вы:

template<typename TTuple, typename TItem>
TTuple& getParentTuple(TItem* mItemPtr)
{
TTuple dummyTuple;

// The std::get by type will not compile if types are duplicated, so
// you do not need a static_assert.
auto dummyElement = (uintptr_t)&std::get<TItem>(dummyTuple);

// Calculate the offset of the element to the tuple base address.
auto offset = dummyElement - (uintptr_t)&dummyTuple;

// Subtract that offset from the passed element pointer.
return *(TTuple*)((uintptr_t)mItemPtr - offset);
}

Обратите внимание, что это создает кортеж один раз, что может иметь нежелательные побочные эффекты или влияние на производительность в некоторых случаях. Я не уверен, есть ли вариант времени компиляции этого.

2

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