I am doing some homework in C++ and I just encountered an error I couldn't fix. I defined a RingBuffer class that stores values, the logic works but I have a problem with the includes. If I don't include the .cpp file with the implementation of the methods I get an "undefined reference to function" error for every single function I defined.
rbtest.cpp (This class was given and is used to test the implementation)
#include <iostream>
#include <stdexcept>
#include "ringbuffer.hpp"
int main(void) {
RingBuffer<int, 3> rb;
rb.print();
std::cout << std::boolalpha;
std::cout << "Empty: " << rb.empty() << " Full: " << rb.full() << std::endl;
rb.push_back(2);
std::cout << "Empty: " << rb.empty() << " Full: " << rb.full() << std::endl;
rb.push_front(1);
rb.push_back(3);
std::cout << "Empty: " << rb.empty() << " Full: " << rb.full() << std::endl;
rb.push_back(4);
std::cout << "Empty: " << rb.empty() << " Full: " << rb.full() << std::endl;
rb.print();
std::cout << "pop_front: " << rb.pop_front() << std::endl;
std::cout << "Empty: " << rb.empty() << " Full: " << rb.full() << std::endl;
std::cout << "pop_front: " << rb.pop_front() << std::endl;
rb.push_back(5);
rb.print();
std::cout << "pop_back: " << rb.pop_back() << std::endl;
std::cout << "pop_back: " << rb.pop_back() << std::endl;
rb.print();
try {
rb.pop_back();
std::cout << "This should not be printed!" << std::endl;
}
catch (std::exception& rangeError) {
std::cout << "Error: " << rangeError.what() << std::endl;
}
}
ringbuffer.hpp
#ifndef X
#define X
#include <iostream>
#include <stdexcept>
/**
* @brief Ring Buffer class
*
* @tparam T typename
* @tparam size int
*/
template <typename T, int size>
class RingBuffer {
private:
int back = 0, front = 0;
T content[size];
int counter = 0;
public:
void push_back(T item);
void push_front(T item);
T pop_back();
T pop_front();
bool full();
bool empty();
void print();
};
#endif
ringbuffer.cpp
#include "ringbuffer.hpp"
/**
* @brief Pushes an Item into the ring buffer from the back
*
* @tparam T
* @tparam size
* @param item
*/
template <typename T, int size>
void RingBuffer<T, size>::push_back(T item) {
if (full()) return;
content[back] = item;
back++;
if (back == size) back = 0;
counter++;
}
/**
* @brief Pushes an item into the ring buffer from the front
*
* @tparam T
* @tparam size
* @param item
*/
template <typename T, int size>
void RingBuffer<T, size>::push_front(T item) {
if (full()) return;
front--;
if (front < 0) front = size - 1;
content[front] = item;
counter++;
}
/**
* @brief Pops an Item from the back and returns it
*
* @tparam T
* @tparam size
* @return T
*/
template <typename T, int size>
T RingBuffer<T, size>::pop_back() {
if (empty()) {
throw std::out_of_range("pop_back on empty buffer");
}
back--;
if (back < 0) back = size - 1;
T item = content[back];
counter--;
return item;
}
/**
* @brief Pops an Item from the front and returns it
*
* @tparam T
* @tparam size
* @return T
*/
template <typename T, int size>
T RingBuffer<T, size>::pop_front() {
if (empty()) {
throw std::out_of_range("pop_front on empty buffer");
}
T item = content[front++];
if (front == size) front = 0;
counter--;
return item;
}
/**
* @brief Checks if ring buffer is full
*
* @tparam T
* @tparam size
* @return true if full
* @return false if not full
*/
template <typename T, int size>
bool RingBuffer<T, size>::full() {
return counter == size;
}
/**
* @brief Checks if ring buffer is empty
*
* @tparam T
* @tparam size
* @return true if empty
* @return false if not empty
*/
template <typename T, int size>
bool RingBuffer<T, size>::empty() {
return counter == 0;
}
/**
* @brief Prints the ring buffer with all its elements front to back, prints "Buffer is empty" if empty
*
* @tparam T
* @tparam size
*/
template <typename T, int size>
void RingBuffer<T, size>::print() {
if (empty()) std::cout << "Buffer is empty" << std::endl;
else {
int i = front;
do {
std::cout << content[i++] << "\t";
if (i >= size) i = 0;
} while (i != back);
std::cout << std::endl;
}
}
Makefile
all: rbtest.cpp ringbuffer.hpp ringbuffer.cpp
g++ -o ringbuffer rbtest.cpp ringbuffer.hpp ringbuffer.cpp
clean:
rm ringbuffer