Нетипизированный связной список

112
23 апреля 2021, 06:40

Как бы я мог получить значение value из своей структуры Val?

#include <iostream>
using namespace std;
template <typename T>
struct Val {
    T value;
};
struct node{
    void* data;
    node* Next;
};

int main() {
   node a{};
   node b{};
   Val<int> c = {41};
   Val<string> d = {"gfdsa"};
   a.data = &c;
   b.data = &d;
   a.Next = &b;
   cout << (a.Next->data);
}
Answer 1

Это плохой подход. Допустим вы написали так

#include <iostream>
#include <memory>
enum NodeType {String, Int};
struct NodeBase {
    NodeType type;
    NodeBase* next;
};
template <typename T>
struct Node: NodeBase {
    std::unique_ptr<T> data;
};

int main() {
   Node<int> a{};
   a.data = std::make_unique<int>(41);
   a.type = NodeType::Int;
   Node<std::string> b{};
   b.data = std::make_unique<std::string>("qwerty");
   b.type = NodeType::String;
   a.next = &b;
   ...
}

Вам КАЖДЫЙ раз при работе со структурой придётся писать что-то наподобие:

switch(a.next->type) {
       case NodeType::Int: {
           Node<int>* nodeInt = dynamic_cast<Node<int>*>(a.next);
           DoSomethingWithInt(*(nodeInt->data));
           break;
       }
       case NodeType::String: {
           Node<std::string>* nodeString = dynamic_cast<Node<std::string>*>(a.next);
           DoSomethingWithString(*(nodeString->data));
           break;
       }
   }

А при добавлении нового типа в список вы просто умрёте в поисках всех таких switсh по всему коду.

Поэтому стоит совсем разные объекты хранить отдельно, а похожие наследовать от общей базы:

#include <iostream>
#include <memory>
#include <sstream>
void DoSomethingWithInt(int data) {
    std::cout << data << std::endl;
}
void DoSomethingWithString(const std::string& data) {
    std::cout << data << std::endl;
}
class NodeValueBase {
public:
    virtual void DoSomething() = 0;
    virtual void SetData(int value) = 0;
    virtual ~NodeValueBase() = default;
};
class NodeValueInt: public virtual NodeValueBase {
public:
    NodeValueInt(int value): data(value) {}; 
    virtual void DoSomething() override {
        DoSomethingWithInt(data);
    }
    virtual void SetData(int value) override {
        data = value;
    }
    int data;
};
class NodeValueString: public virtual NodeValueBase {
public:
    NodeValueString(const std::string& value): data(value) {};
    virtual void DoSomething() override {
        DoSomethingWithString(data);
    }
    virtual void SetData(int value) override {
        std::stringstream ss;
        ss << value;
        data = ss.str();
    }
    std::string data;
};
template <typename T>
struct Node {
    std::unique_ptr<T> data;
    Node* next;
};
template<typename D, typename B>
std::unique_ptr<D> static_cast_ptr(std::unique_ptr<B>&& base)
{
    return std::unique_ptr<D>(static_cast<D*>(base.release()));
}
int main() {
   Node<NodeValueBase> a{};
   a.data = static_cast_ptr<NodeValueBase, NodeValueInt>(
       std::make_unique<NodeValueInt>(41));
   Node<NodeValueBase> b{};
   b.data = static_cast_ptr<NodeValueBase, NodeValueString>(
       std::make_unique<NodeValueString>("qwerty"));
   a.next = &b;
   a.next->data->DoSomething();
   a.next->data->SetData(123);
   a.next->data->DoSomething();
}
Answer 2

Перед тем как "разыменовать" указатель на void, нужно сначала привести тип.

cout << ((Val<string>*)a.Next->data)->value << endl;

И добавь в начале #include<string>

READ ALSO
Code blocks linux не компилируется алиас типа

Code blocks linux не компилируется алиас типа

Вопрос из разряда для начинающих, но учитывая что я под линуксом делаю свой первый проект - думаю это простительно

113
Параллельный вызов boost.python

Параллельный вызов boost.python

Пытаюсь из кода на python, распараллеленного с помощью ThreadPoolExecutor вызвать код на C++Создается впечатление, что в момент входа в C++ функцию все питоновские...

115
jQuery Validate plugin - не срабатывает правило для пароля

jQuery Validate plugin - не срабатывает правило для пароля

Хочу добавить некоторые требования к паролю:

98