0

I have created a simple, yet unfinished code, for a Queue in C++ 14 - i haven't touched C++ for almost 3 years now, wanted to refresh my memory but I don't know what I am doing wrong.

CLion throws the following error:

====================[ Build | test | Debug ]====================================
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build "/Users/molybdenum/Desktop/Various Projects/C++/test/cmake-build-debug" --target test
[4/4] Linking CXX executable test
FAILED: test 
: && /Library/Developer/CommandLineTools/usr/bin/c++ -g -arch arm64 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names  CMakeFiles/test.dir/main.cpp.o CMakeFiles/test.dir/dataStructs/Queue.cpp.o CMakeFiles/test.dir/dataStructs/Node.cpp.o -o test   && :
Undefined symbols for architecture arm64:
  "dataStructs::Queue<int>::print()", referenced from:
      _main in main.cpp.o
  "dataStructs::Queue<int>::append(int)", referenced from:
      _main in main.cpp.o
  "dataStructs::operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, dataStructs::Queue<int>)", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

My code:

dataStructs/Node.h

#ifndef TEST_NODE_H
#define TEST_NODE_H

namespace dataStructs {
    template <class T>
    class Node {
    private:
        Node *pred = nullptr;
        Node *succ = nullptr;
        T value;

    public:
        Node() = default;
        explicit Node(T v);
        ~Node() = default;
        void setSucc(Node* n);
        Node<T>* getSucc();
        void setPred(Node* n);
        Node<T>* getPred();
        T getVal();
    };
}

#endif //TEST_NODE_H

dataStructs/Node.cpp

#include "Node.h"

namespace dataStructs {
    template<class T>
    Node<T>::Node(T v) {
        this->value = v;
    }

    template <class T>
    void Node<T>::setSucc(Node* n) {
        this->succ = n;
    }

    template<class T>
    Node<T> *Node<T>::getSucc() {
        return this->succ;
    }

    template <class T>
    void Node<T>::setPred(Node* n) {
        this->pred = n;
    }

    template<class T>
    Node<T> *Node<T>::getPred() {
        return this->pred;
    }

    template<class T>
    T Node<T>::getVal() {
        return value;
    }
}

dataStructs/Queue.h

#ifndef TEST_QUEUE_H
#define TEST_QUEUE_H

#include <string>
#include "Node.h"

using namespace std;

namespace dataStructs {
    template<class T>

    class Queue {
    public:
        enum Type {
            fifo, lifo
        };
        enum Sorting {
            ascending, descending
        };
    private:
        Type t = fifo;
        int c = 0;
        Node<T>* head = nullptr;
        Node<T>* last = nullptr;

    public:
        Queue() = default;

        ~Queue() = default;

        explicit Queue(Type type);

        void append(T val);

        void sort(Sorting sort=ascending);

        string print();

        friend ostream &operator<<(ostream &ostream, Queue<T> queue);
    };

    template <class T>
    ostream &operator<<(ostream &ostream, Queue<T> queue) {
        Node<T>* walker = queue.head;
        string output = "[";
        while (walker != nullptr) {
            output += to_string(walker->getVal());
            if (walker->getSucc() != nullptr &&
                walker->getSucc()->getSucc() != nullptr) {
                output += ", ";
            }
            walker = walker->getSucc();
        }
        output += "]";
        return ostream << output;
    }
}

#endif //TEST_QUEUE_H

dataStructs/Queue.cpp

#include "Queue.h"

namespace dataStructs {
    template<class T>
    Queue<T>::Queue(Type type) {
        if (type != fifo || type != lifo) {
            throw invalid_argument("Available types for Queue are fifo or lifo");
        }
        this->t = type;
    }

    template<class T>
    void Queue<T>::append(T val) {
        if (head == nullptr) {
            auto* temp = new Node<T>(val);
            head = temp;
            temp->setPred(head);
            last = temp;
            temp->setSucc(last);
            c++;
        }
    }

    template<class T>
    void Queue<T>::sort(Queue::Sorting sort) {

    }

    template<class T>
    string Queue<T>::print() {
        Node<T>* walker = head;
        string output = "[";
        while (walker != nullptr) {
            output += to_string(walker->getVal());
            if (walker->getSucc() != nullptr &&
                walker->getSucc()->getSucc() != nullptr) {
                output += ", ";
            }
            walker = walker->getSucc();
        }
        output += "]";
        return output;
    }
}

main.cpp

#include <iostream>
#include "dataStructs/Queue.h"

using namespace std;
using namespace dataStructs;

int main() {
    auto queue = Queue<int>();
    queue.append(2);
    queue.print();
    cout << queue << endl;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.21)
project(test)

set(CMAKE_CXX_STANDARD 14)

include_directories(.)

add_executable(test
        ./main.cpp
        ./dataStructs/Queue.cpp
        ./dataStructs/Queue.h
        ./dataStructs/Node.cpp
        ./dataStructs/Node.h)

  • Templates need to be fully implemented in the header file or manually instantiated for every type they're used with – Alan Birtles Dec 18 '21 at 08:35

0 Answers0