0

I am using Visual Studio Community 2015 with the newest version of the Visual Micro Arduino Plugin, however I also tried compiling my code in the Arduino IDE. When compiling my code, there is the following error:

Compiling debug version of 'Autonomous_Car' for 'Arduino/Genuino Uno'
Autonomous_Car.cpp.o:In function `setup
Autonomous_Car.ino:undefined reference to `List<UpdateAble>  List()
Autonomous_Car.ino:undefined reference to `List<UpdateAble>  ~List() 
collect2.exe*:error: ld returned 1 exit status 
Error creating .elf

Some info

  • Adding #include "List.cpp" fixes the error, however this does not seem like valid C++.
  • The files do not lay in any sub-directory
  • In my Project Explorer both List.h and List.cpp are added to the project.
  • I also removed both files from the project, deleted them and added them again
  • I deleted the ´%AppData%\Local\Arduino15´ directory
  • I am fairly new to C++ and Arduino, there might be something obvious, what I just can't find

Autonomous_Car.ino

#include "List.h"
#include "UpdateAble.h"

void setup()
{
    List<UpdateAble>* myList = new List<UpdateAble>();
    myList->GetCount();

    delete myList;
}

List.h

#ifndef _LIST_h
#define _LIST_h

#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif


template <class T>
class List {
public:
    void Add(T &item);
    bool Contains(T &item);
    bool Remove(T &item);
    void Clear();
    int IndexOf(T &item);
    T* GetItem(int index);

    inline int GetCount() { return count; };
    inline int GetCapacity() { return capacity; };

    List();
    ~List();
private:
    void EnsureCapacity(int capacity);

    int count;
    int capacity;
    T** items;
};

#endif

List.cpp

#include "List.h"

// Constructor
template <class T>
List<T>::List() {
    List::capacity = 4;
    List::count = 0;

    List::items = new T*[List::capacity];
}

// Cleanup
template <class T>
List<T>::~List() {
    delete[] List::items;
}

template <class T>
void List<T>::EnsureCapacity(int capacity) {
    if (List::capacity < capacity) {
        // Kapazität verdoppeln
        List::capacity = List::capacity * 2;

        // Speicher für neues array reservieren
        T** newArray = new T*[List::capacity];

        // Array kopieren
        for (unsigned int i = 0; i < List::count; i++) {
            newArray[i] = List::items[i];
        }

        // Speicher von alten array freigeben und neues array zuweisen
        delete[] List::items;
        List::items = newArray;
    }
}

// Adds a new item to the list
template <class T>
void List<T>::Add(T &item) {
    List::EnsureCapacity(count + 1);

    List::items[count] = item;
    List::count++;
}

// Gets whether the list contains an item or not
template <class T>
bool List<T>::Contains(T &item) {
    return List::IndexOf(item) != -1;
}

template <class T>
bool List<T>::Remove(T &item) {
    int index = List::IndexOf(item);

    // If the item does not exist, we cannot remove it
    if (index == -1) return false;

    // Move every item behind our item one further
    for (int i = index + 1; i < List::count; i++) {
        List::items[i - 1] = List::items[i];
    }

    List::count--;
}

// Release the heap 
template <class T>
void List<T>::Clear() {
    for (int i = 0; i < List::count; i++) {
        delete List::items[i];
    }

    delete[] List::items;
}

// Gets an index of an item, -1 if not found
template <class T>
int List<T>::IndexOf(T &item) {
    for (int i = 0; i < List::count; i++) {
        if (List::items[i] == item) {
            return i;
        }
    }

    return -1;
}

template <class T>
T* List<T>::GetItem(int index) {
    if (index < List::count && index >= 0) {
        return List::items[index];
    }

    return 0;
}

I'd be very glad, if we can find the solution.

1

You're using a template class. A template class is a special corner case that breaks the "code in .cpp and definitions in .h files" rule.

Because it's a template it can't be pre-compiled - it needs to be specially compiled each time it is used, so that it can get the right values compiled in to the template place-holders, which are provided by the CU that has the template class included with it.

Because of that it is one of the rare cases where the code has to be in the header file.

For a full example you can take a look at my Average library which is a fully templated class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.