C ++ Восстановить из void * элемент, указывающий на неизвестный ассоциативный контейнер - PullRequest
0 голосов
/ 05 сентября 2018

Я создал структуру, готовую принимать итераторы из разных ассоциативных контейнеров (set, map, multiset и т. Д.) И хранить указатель на этот элемент.

set<ObjX> SetX {...}
set<ObjY> SetY {...}
map<ObjZ, Data> MapZ {...}

struct INPosition {
    INPosition(set<ObjX>::const_iterator pTMP)       : POINTER(&*pTMP) {}
    INPosition(set<ObjY>::const_iterator pTMP)       : POINTER(&*pTMP) {}
    INPosition(map<ObjZ, Data>::const_iterator pTMP) : POINTER(&*pTMP) {}

    void show() { cout << POINTER << '\t' << typeid(POINTER).name() << '\n'; }

    private:
       const void* POINTER;
};

INPosition TTT(SetY.find(ObjY(2)));

cout << "Addr SetY  Element 1: " << &*SetY.find(1) << '\t'<< typeid(&*SetY.find(1)).name() << '\n';
cout << "Addr SetY  Element 2: " << &*SetY.find(2) << '\t'<< typeid(&*SetY.find(2)).name() << '\n';
cout << "Addr POINTER (Elm 2): "; TTT.show();

Результат:

Addr SetY  Element 1: 0x5654ee2096d0      PKSt10ObjYI10MyClassSt14default_deleteIS0_EE
Addr SetY  Element 2: 0x5654ee209720      PKSt10ObjYI10MyClassSt14default_deleteIS0_EE
Addr POINTER (Elm 2): 0x5654ee209720      PKv                                          //The typeid.name supposes to be the same than Element 2 above???

POINTER сохраняет адрес элемента, но typeid не распознает этот элемент, который я должен был (То же, что элемент 2).

Мой вопрос: как создать член функции, который возвращает приведенный тип с правильным типом? Другими словами, восстановите итератор. Примерно так:

auto Iterator() {
     return auto_cast(POINTER);
}

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Вам не нужно void*, вам нужно std::variant<ObjX*, ObjY*, ObjZ*>.

Ваш show() может использовать std::variant<...>::index(), который будет 0, 1 или 2 для X, Y или Z.

0 голосов
/ 05 сентября 2018

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

Вы должны хранить некоторую информацию о типе рядом с void*. Например, используя enum:

struct INPosition {
    enum class ObjType { SET_X, SET_Y, MAP_Z };

    INPosition(std::set<ObjX>::const_iterator pTMP)       : element(&*pTMP), objType(ObjType::SET_X) {}
    INPosition(std::set<ObjY>::const_iterator pTMP)       : element(&*pTMP), objType(ObjType::SET_Y) {}
    INPosition(std::map<ObjZ, Data>::const_iterator pTMP) : element(&*pTMP), objType(ObjType::MAP_Z) {}

private:
    const void* element;
    const ObjType objType;
};

Этого само по себе недостаточно, чтобы доставить вас туда, куда вы хотите, потому что вы не можете возвращать разные типы из одной и той же функции. Какой тип возврата вы ожидаете получить auto Iterator()?

Урок здесь : используя void*, вы явно побеждаете (или оставляете) систему типов C ++, но не можете написать никакой полезный код C ++ вне ее. Возвращение в систему типов из void* требует некоторых усилий.

Вы могли бы реально сделать эту работу, используя (перегруженный) аргумент функтора для достижения чего-то полезного:

template<class OverloadedFunctor>
auto apply(OverloadedFunctor f)
{
    switch (objType)
    {
    case ObjType::SET_X:
        return f(*static_cast<const std::set<ObjX>::value_type*>(element));
    case ObjType::SET_Y:
        return f(*static_cast<const std::set<ObjY>::value_type*>(element));
    case ObjType::MAP_Z:
        return f(*static_cast<const std::map<ObjZ, Data>::value_type*>(element));
    }
}

Тогда, если у вас был перегруженный функтор, который мог бы делать что-то полезное с каждым из этих типов, вы могли бы применить его так:

struct MyOverloadedFunctor
{
    void operator()(const ObjX& x) const;
    void operator()(const ObjY& y) const;
    void operator()(const std::pair<ObjZ, Data>& zd) const;
};

std::set<ObjY> setY;
setY.emplace();
INPosition position(setY.begin());
MyOverloadedFunctor myOverloadedFunctorInstance;
position.apply(myOverloadedFunctorInstance); // will call the second overload.

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...