Question about using templates

Hey Guys,

Thanks in advance for looking at my question. So I'm trying to learn C++ and I'm working on templates. I created a simple linked list class and tested it to ensure it worked. Then I tried add templates as an exercise in learning how they work. Obviously since I'm here I'm having trouble. Any help getting my example code to work would be appreciated.

Additionally, I have a few generic template questions.
1) What do I need to do when I have multiple classes involved with templates? I believe that is my problem here.
2) Is it simpler to declare the internal class named Node externally? Or maybe just make it a struct?
3) I've seen many comments about how you should just define all your template code in a header file. Isn't this what the keyword export is for? Why would I not want to do this?
4) Since the overloaded << operator only supports numeric types of data due to my implementation I was going to implement a class specialization for strings as follow up exercise. In my experience in java it would just be easier to create an interface and only work with objects that implement it. In your C++ experience is it more likely to see a completely virtual/abstract base class (AKA pseudo interface) or to implement class specialization for templates?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include <iostream>

template <typename kind>
class LinkedList {
    private:
        class Node {
            public:
                Node *next;
                kind value;
        };
        Node<kind> *firstNode;

    public:
        LinkedList(): firstNode(NULL) {};
        LinkedList(kind value);
        LinkedList(const LinkedList<kind>& list);
        ~LinkedList();

    void insert(kind value);
    bool search(kind value);
    bool remove(kind value);

    friend std::ostream& operator << (std::ostream& out_stream, const LinkedList<kind>& list);
};

template <typename kind>
inline LinkedList<kind>::LinkedList(kind value)
{
    firstNode = new Node;
    firstNode->next = NULL;
    firstNode->value = value;
}

template <typename kind>
inline LinkedList<kind>::LinkedList(const LinkedList<kind>& list)
{
    Node<kind> *tempNode;
    Node<kind> *oldNodes = list.firstNode;
    Node<kind> *newNodes= NULL;
    

    while (oldNodes != NULL)
    {
        tempNode = new Node<kind>;
        if (newNodes == NULL)
            //This is the first node
            firstNode = tempNode;
        else
            //Else setup the chain
            newNodes->next = tempNode;

        tempNode->value = oldNodes->value;

        if (oldNodes->next == NULL)
            //This is the last node
            tempNode->next = NULL;

        newNodes = newNodes->next;
        oldNodes = oldNodes->next;
    }
}

template <typename kind>
inline LinkedList<kind>::~LinkedList()
{
    Node<kind> *currentNode = firstNode;
    Node<kind> *previousNode = NULL;

    while (currentNode != NULL)
    {
        previousNode = currentNode;
        currentNode = currentNode->next;
        delete previousNode;
    }
}

template <typename kind>
inline void LinkedList<kind>::insert(kind value)
{
    Node<kind> *newNode = new Node<kind>;

    newNode->value = value;
    newNode->next = firstNode;
    firstNode = newNode;
}

template <typename kind>
inline bool LinkedList<kind>::search(kind value)
{
    Node<kind> *currentNode = firstNode;

    while (currentNode != NULL)
    {
        if (currentNode->value == value)
            break;
        currentNode = currentNode->next;
    }

    if (currentNode == NULL)
        return false;
    else
        return true;
}

template <typename kind>
inline bool LinkedList<kind>::remove(kind value)
{
    Node<kind> *currentNode = firstNode;
    Node<kind> *previousNode = NULL;

    while (currentNode != NULL)
    {
        if (currentNode->value == value)
        {
            //If it is the first node
            if (previousNode == NULL)
            {
                firstNode = currentNode->next;
                delete currentNode;
            }
            else
            {
                previousNode->next = currentNode->next;
                delete currentNode;
            }
            break;
        }
        previousNode = currentNode;
        currentNode = currentNode->next;
    }

    if (currentNode == NULL)
        return false;
    else
        return true;
}

template <typename kind>
inline std::ostream& operator<<(std::ostream& out_stream, const LinkedList<kind>& list)
{
    std::string result;
    //LinkedList<kind>::Node *currentNode = list.firstNode;
    LinkedList<kind>::template Node<kind> *currentNode = list.firstNode;
    int nodeNumber = 0;

    while (currentNode != NULL) {
        //I know this won't work for non numeric data
        result += "Node: " + std::to_string(nodeNumber) + " Value: " + std::to_string(currentNode->value) + '\n';
        ++nodeNumber;
        currentNode = currentNode->next;
    }

    out_stream << result;

    return out_stream;
}

int main()
{
    LinkedList<int> myList;
    int testValue;

    myList.insert(3);
    myList.insert(2);
    myList.insert(1);

    std::cout << "My list contains:\n" << myList;

    std::cout << "Searching for the value 5\n";
    if (myList.search(5))
        std::cout << "I found an entry I shouldn't have\n";
    else
        std::cout << "I didn't find the entry which is expected\n";

    for (int i = 1; i < 4; ++i)
    {
        std::cout << "Searching for the value " << i << ": ";
        if (myList.search(i))
            std::cout << "I found the entry\n";
        else
            std::cout << "I didn't the entry\n";
    }

    std::cout << "Attempting to remove a non-existant entry from the list\n";
    if (myList.remove(5))
        std::cout << "Somehow I removed a non-existant entry\n";
    else
        std::cout << "Failed to remove entry. This is good since it didn't exist\n";
    
    std::cout << "Printing the list to ensure it's unchanged\n";
    std::cout << myList;

    testValue = 1;
    std::cout << "Removing entry with value " << testValue << '\n';
    if (myList.remove(testValue))
        std::cout << "Successfully removed entry\n";
    else
        std::cout << "failed to remove entry\n";
    std::cout << "Printing the list\n" << myList;
}
Last edited on
> Any help getting my example code to work would be appreciated.
first you need to tell us what the problem is. If you've got compile errors then you should post them.

> Is it simpler to declare the internal class named Node externally?
¿do you want the client code to create nodes?

> Or maybe just make it a struct?
that's what it is.

> Since the overloaded << operator only supports numeric types of data due to my implementation
¿why can't you make your implementation generic?
1
2
3
4
5
    while (currentNode != NULL) {
        out_stream << "Node: " << std::to_string(nodeNumber) << " Value: " << currentNode->value << '\n';
        ++nodeNumber;
        currentNode = currentNode->next;
    }
as long as you can print a `kind', you can print a list of `kind'
Topic archived. No new replies allowed.