Tree with Nodes can be 3 different types (string, int or float)

Viewed 176

It is required to implement an arbitrary tree, where each node can be a string, an integer or a real number, and have any number of children, also one of these three types (children can be of different types). While designing a class for a node, I got two ideas on how to do this:

template <typename T>
class tree_node
{
    using value_type = typename std::enable_if
        <
            std::is_same<std::string, T>::value ||
            std::is_same<int, T>::value ||
            std::is_same<float, T>::value, T
        >::type;
    value_type data;
    std::vector<??????> children;// What type must be there?
public:
...

and

    struct node_data {};
struct str_node: public node_data
{
    std::string data;
    str_node(std::string &str): data(str) {};
};
struct int_node: public node_data
{
    int data;
    int_node(int n): data(n) {};
};
struct float_node: public node_data
{
    float data;
    float_node(float f): data(f) {};
};
 
class tree_node
{
    std::shared_ptr<node_data> val;
    std::vector<std::shared_ptr<node_data>> children;
public:
....

Is there an elegant solution (for example, some design patterns) to this problem?

2 Answers

Maybe Composite pattern would help you:

#include <iostream>
#include <string>
#include <vector>

struct INode {
    virtual void print() = 0;
};

class CompositeNode : public INode {
private:
    std::vector<INode*> nodes;

public:
    void add(INode* node) {
        nodes.push_back(node);
    }

    void print() override {
        for(INode* node : nodes) {
            node->print();
        }
    }
};

class IntNode : public INode {
private:
    int value;
public:
    IntNode(int i) {
        value = i;
    }

    void print() override {
        std::cout << value << std::endl;
    }
};

class FloatNode : public INode {
private:
    float value;
public:
    FloatNode(float i) {
        value = i;
    }

    void print() override {
        std::cout << value << std::endl;
    }
};

class StrNode : public INode {
private:
    std::string value;
public:
    StrNode(std::string s) {
        value = s;
    }

    void print() override {
        std::cout << this->value << std::endl;
    }
};

int main () {
    StrNode s1("node1string");
    IntNode i1(1);
    FloatNode f1(1.1f);

    CompositeNode cnode1;
    cnode1.add(&s1);
    cnode1.add(&i1);
    cnode1.add(&f1);

    StrNode s2("node2string");
    IntNode i2(2);
    FloatNode f2(2.1f);

    CompositeNode cnode2;
    cnode2.add(&f2);
    cnode2.add(&i2);
    cnode2.add(&s2);

    CompositeNode cnode;
    cnode.add(&cnode1);
    cnode.add(&cnode2);

    cnode.print();
}
template <typename T>
class tree_node
{
    static_assert(std::is_same_v<int, T> || std::is_same_v<float, T>
        || std::is_same_v<std::string, T>, "...your error message");
    using value_type = T;
    value_type data;
    std::list<std::shared_ptr<value_type>> children;
   //...
};
Related