0

I have 4 files node.hpp, node.cpp, linked_list.hpp and linked_list.cpp. There codes are respectively below.

#ifndef NODE
#define NODE

template <typename T>
struct Node {
    T        data;
    Node<T>* next;

    Node(const T& data);
    Node(const T& data, const Node<T>* next);
};

#endif  // NODE

#include "node.hpp"

template <typename T>
Node<T>::Node(const T& data) : data(data), next(nullptr) {}

template <typename T>
Node<T>::Node(const T& data, const Node<T>* next) : data(data), next(next) {}
#ifndef LINKED_LIST
#define LINKED_LIST

#include <cstddef>

#include "node.hpp"

template <typename T>
class LinkedList {
public:

    LinkedList();
    LinkedList(const T& data);
    LinkedList(const LinkedList& other);

    ~LinkedList();

    void push_front(const T& data);
    void push_back(const T& data);
    void pop_front();
    void pop_back();

    T front() const;
    T back() const;

    T    get(const int& index) const;
    void set(const int& index, const T& data);

    void insert(const size_t& index, const T& data);
    void remove(const size_t& index);
    int  getSize() const;

    bool isEmpty() const;
    void clear();

    void print() const;

    LinkedList& operator=(const LinkedList& other);
    bool        operator==(const LinkedList& other) const;
    bool        operator!=(const LinkedList& other) const;
    T           operator[](const size_t& index) const;
    T&          operator[](const size_t& index);

private:

    Node<T>* head;
    size_t   size = 0;
};

#endif  // LINKED_LIST

#include "linked_list.hpp"

#include <iostream>

template <typename T>
LinkedList<T>::LinkedList() : head(nullptr), size(0) {}

template <typename T>
LinkedList<T>::LinkedList(const T& data) : head(new Node<T>(data)), size(1) {}

template <typename T>
LinkedList<T>::LinkedList(const LinkedList& other) {
    this->head = nullptr;
    this->size = 0;

    Node<T>* current = other.head;
    while (current != nullptr) {
        this->push_back(current->data);
        current = current->next;
        size++;
    }
}

template <typename T>
LinkedList<T>::~LinkedList() {
    this->clear();
}

template <typename T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList& other) {
    if (this == &other) return *this;

    this->clear();

    Node<T>* current = other.head;
    while (current != nullptr) {
        this->push_back(current->data);
        current = current->next;
    }

    return *this;
}

template <typename T>
bool LinkedList<T>::operator==(const LinkedList& other) const {
    if (size != other.size) return false;

    Node<T>* current1 = head;
    Node<T>* current2 = other.head;
    while (current1 != nullptr) {
        if (current1->data != current2->data) return false;
        current1 = current1->next;
        current2 = current2->next;
    }
    return true;
}

template <typename T>
bool LinkedList<T>::operator!=(const LinkedList& other) const {
    return !(*this == other);
}

template <typename T>
void LinkedList<T>::push_front(const T& data) {
    Node<T>* newNode = new Node<T>(data);
    newNode->next    = head;
    head             = newNode;
    ++size;
}

template <typename T>
void LinkedList<T>::push_back(const T& data) {
    if (head == nullptr)
        head = new Node<T>(data);
    else {
        Node<T>* current = head;
        while (current->next != nullptr) current = current->next;
        current->next = new Node<T>(data);
    }
    ++size;
}

template <typename T>
void LinkedList<T>::pop_front() {
    if (head == nullptr) return;

    Node<T>* temp = head;
    head          = head->next;
    delete temp;
    --size;
}

template <typename T>
void LinkedList<T>::pop_back() {
    if (this->head == nullptr) return;

    if (this->head->next == nullptr) {
        delete this->head;
        this->head = nullptr;
    } else {
        Node<T>* current = this->head;
        while (current->next->next != nullptr) current = current->next;
        delete current->next;
        current->next = nullptr;
    }
    --size;
}

template <typename T>
T LinkedList<T>::front() const {
    return this->head->data;
}

template <typename T>
T LinkedList<T>::back() const {
    Node<T>* current = this->head;
    while (current->next != nullptr) current = current->next;
    return current->data;
}

template <typename T>
T LinkedList<T>::get(const int& index) const {
    if (index < 0 || index >= size) return T();
    Node<T>* current = this->head;
    for (int i = 0; i < index; ++i) current = current->next;
    return current->data;
}

template <typename T>
void LinkedList<T>::set(const int& index, const T& data) {
    if (index < 0 || index >= size) return;
    Node<T>* current = this->head;
    for (int i = 0; i < index; ++i) current = current->next;
    current->data = data;
}

template <typename T>
void LinkedList<T>::insert(const size_t& index, const T& data) {
    if (index < 0 || index > size) return;

    if (index == 0)
        push_front(data);
    else {
        Node<T>* current = this->head;

        for (size_t i = 0; i < index - 1; ++i) current = current->next;

        Node<T>* newNode = new Node<T>(data);
        newNode->next    = current->next;
        current->next    = newNode;
        ++size;
    }
}

template <typename T>
void LinkedList<T>::remove(const size_t& index) {
    if (index < 0 || index >= size) return;

    if (index == 0)
        pop_front();
    else {
        Node<T>* current = this->head;
        for (size_t i = 0; i + 1 < index; ++i) current = current->next;

        Node<T>* temp = current->next;
        current->next = current->next->next;
        delete temp;
        --size;
    }
}

template <typename T>
int LinkedList<T>::getSize() const {
    return size;
}

template <typename T>
bool LinkedList<T>::isEmpty() const {
    return size == 0;
}

template <typename T>
void LinkedList<T>::clear() {
    while (this->head != nullptr) pop_front();
}

template <typename T>
void LinkedList<T>::print() const {
    Node<T>* current = this->head;
    while (current != nullptr) {
        std::cout << current->data << " ";
        current = current->next;
    }
    std::cout << std::endl;
}

template <typename T>
T LinkedList<T>::operator[](const size_t& index) const {
    return get(index);
}

template <typename T>
T& LinkedList<T>::operator[](const size_t& index) {
    if (index < 0 || index >= size) return T();

    Node<T>* current = this->head;
    for (int i = 0; i < index; ++i) current = current->next;

    return current->data;
}

int main() {
    LinkedList<int> list;
    list.push_back(1);
    list.push_back(2);
    list.push_back(3);
    list.push_back(4);

    list.print();

    list.remove(2);

    list.print();

    return 0;
}

makefile is,

linked_list:
    g++ linked_list.cpp node.cpp -Wall -o linked_list
    ./linked_list
    rm ./linked_list

The compiler gives following errors,

make linked_list
g++ linked_list.cpp node.cpp -Wall -o linked_list
/usr/bin/ld: /tmp/ccV1cNdz.o: in function `LinkedList<int>::push_back(int const&)':
/media/meesumaliqazalbash/Personal/Data-Structures/cpp/linked_list.cpp:74: undefined reference to `Node<int>::Node(int const&)'
/usr/bin/ld: /media/meesumaliqazalbash/Personal/Data-Structures/cpp/linked_list.cpp:78: undefined reference to `Node<int>::Node(int const&)'
collect2: error: ld returned 1 exit status
make: *** [makefile:17: linked_list] Error 1

I have tried altering the command and there is no success.

linked_list:
    g++ -c node.cpp -Wall -o node.o
    g++ -c linked_list.cpp -Wall -o linked_list.o
    g++ node.o linked_list.o -Wall -O -o linked_list -g
    ./linked_list
    rm ./linked_list

Error

make linked_list
g++ -c node.cpp -Wall -o node.o
g++ -c linked_list.cpp -Wall -o linked_list.o
g++ node.o linked_list.o -Wall -O -o linked_list -g
/usr/bin/ld: linked_list.o: in function `LinkedList<int>::push_back(int const&)':
linked_list.cpp:(.text._ZN10LinkedListIiE9push_backERKi[_ZN10LinkedListIiE9push_backERKi]+0x3b): undefined reference to `Node<int>::Node(int const&)'
/usr/bin/ld: linked_list.cpp:(.text._ZN10LinkedListIiE9push_backERKi[_ZN10LinkedListIiE9push_backERKi]+0x86): undefined reference to `Node<int>::Node(int const&)'
collect2: error: ld returned 1 exit status
make: *** [makefile:19: linked_list] Error 1

I made a raytracer a month ago and there I was linking multiple files and it shows no problem. I guess there maybe some issue with my VSCode settings.

This is task.json.

{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: g++ build active file",
            "command": "/usr/bin/g++",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": ["$gcc"],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        }
    ],
    "version": "2.0.0"
}

This is settings.json.

{
    "files.associations": {
        "array": "cpp",
        "atomic": "cpp",
        "bit": "cpp",
        "*.tcc": "cpp",
        "compare": "cpp",
        "list": "cpp",
        "string": "cpp",
        "unordered_map": "cpp",
        "vector": "cpp",
        "algorithm": "cpp",
        "chrono": "cpp",
        "functional": "cpp",
        "memory": "cpp",
        "memory_resource": "cpp",
        "optional": "cpp",
        "random": "cpp",
        "ratio": "cpp",
        "system_error": "cpp",
        "tuple": "cpp",
        "type_traits": "cpp",
        "cmath": "cpp",
        "fstream": "cpp",
        "future": "cpp",
        "iomanip": "cpp",
        "istream": "cpp",
        "limits": "cpp",
        "numeric": "cpp",
        "ostream": "cpp",
        "sstream": "cpp",
        "stdexcept": "cpp",
        "stop_token": "cpp",
        "streambuf": "cpp",
        "string_view": "cpp",
        "thread": "cpp",
        "utility": "cpp",
        "typeinfo": "cpp",
        "valarray": "cpp",
        "variant": "cpp",
        "*.inc": "cpp",
        "iostream": "cpp",
        "bitset": "cpp",
        "cctype": "cpp",
        "clocale": "cpp",
        "codecvt": "cpp",
        "concepts": "cpp",
        "condition_variable": "cpp",
        "cstdarg": "cpp",
        "cstddef": "cpp",
        "cstdint": "cpp",
        "cstdio": "cpp",
        "cstdlib": "cpp",
        "cstring": "cpp",
        "ctime": "cpp",
        "cwchar": "cpp",
        "cwctype": "cpp",
        "deque": "cpp",
        "map": "cpp",
        "set": "cpp",
        "unordered_set": "cpp",
        "exception": "cpp",
        "iterator": "cpp",
        "source_location": "cpp",
        "initializer_list": "cpp",
        "iosfwd": "cpp",
        "mutex": "cpp",
        "new": "cpp",
        "numbers": "cpp",
        "semaphore": "cpp",
        "cinttypes": "cpp"
    }
}
grad f
  • 47
  • 5
  • 1
    Linkers cannot link templates, that is why templates must be placed in header files, so the compiler sees them. – john Jan 03 '23 at 13:01

0 Answers0