Search code examples
c++templatesunresolved-external

C++ Unresolved External - Template


I am getting an unresolved external compile error when compiling my template classes. I have separated the code into .h and .cpp files.

I read some posts and now I understand that this will not work due to linking issues as explained in this post.

  1. include the full definition of the member function in the template's header file and not have a source file for the template,

  2. define all the member functions in the template's source file as "inline", or

  3. define the member functions in the template's source with the "export" keyword. Unfortunately this isn't supported by a lot of compilers.

However, none of these options will work since I have conversion functions between a number of these template functions (which results in a cross include compile issue).

How do I fix this issue?

EDIT: Include Code

StaticArray.h

template<typename T>
class Array;

template<typename T, unsigned int N>
class StaticArray
{
protected:
    T* _data[N];
public:
    StaticArray();
    StaticArray(const StaticArray<T,N>& other);
    ~StaticArray();

    void Release(unsigned int index);
    void Release(T* data);
    void ReleaseAll();

    Array<T> ToArray();

    bool operator == (const StaticArray<T,N>& other);
    bool operator != (const StaticArray<T,N>& other);
    T*& operator [] (unsigned int index) const;
    StaticArray<T,N>& operator = (const StaticArray<T,N>& other);
};

StaticArray.cpp

#pragma region StaticArray::CoreMethods

template<typename T, unsigned int N>
StaticArray<T, N>::StaticArray()
{
    for (unsigned int i = 0; i < N; i++)
    {
        this->_data[i] = null;
    }
}

template<typename T, unsigned int N>
StaticArray<T, N>::StaticArray(const StaticArray<T,N>& other)
{
    for (unsigned int i = 0; i < N; i++)
    {
        this->_data[i] = other._data[i];
    }
}

template<typename T, unsigned int N>
StaticArray<T, N>::~StaticArray()
{

}

#pragma endregion

#pragma region StaticArray::Methods

template<typename T, unsigned int N>
void StaticArray<T,N>::Release(unsigned int index)
{
    if (index < N)
    {
        delete this->_data[i];
        this->_data[i] = null;
    }
    else
    {
        throw new Exception::IndexOutOfBoundsException("StaticArray accessed at index greater than N.");
    }
}

template<typename T, unsigned int N>
void StaticArray<T,N>::Release(T* data)
{
    if (data == null)
    {
        throw new Exception::InvalidArgumentException("StaticArray Release call argument must not be null.");
    }

    for (unsigned int i = 0; i < N; i++)
    {
        if (this->_data[i] == data)
        {
            this->Release(i);
            return;
        }
    }

    throw new Exception::InvalidArgumentException("StaticArray Release call argument was not in the array.");
}

template<typename T, unsigned int N>
void StaticArray<T,N>::ReleaseAll()
{
    for (unsigned int i = 0; i < N; i++)
    {
        if (this->_data[i] != null)
        {
            delete this->_data[i];
            this->_data[i] = null;
        }
    }
}

template<typename T, unsigned int N>
Array<T> StaticArray<T,N>::ToArray()
{
    Array<T> ret(N);

    for (unsigned int i = 0; i < N; i++)
    {
        ret[i] = this->_data[i];
    }

    return ret;
}

#pragma endregion

#pragma region StaticArray::OperatorOverloads

template<typename T, unsigned int N>
bool StaticArray<T,N>::operator == (const StaticArray<T,N>& other)
{
    for (unsigned int i = 0; i < N; i++)
    {
        if (this->_data[i] != other._data[i])
        {
            return false;
        }
    }

    return true;
}

template<typename T, unsigned int N>
bool StaticArray<T,N>::operator != (const StaticArray<T,N>& other)
{
    return !((*this) == other);
}

template<typename T, unsigned int N>
T*& StaticArray<T, N>::operator[](unsigned int index) const
{
    if (index < N)
    {
        return this->_data[index];
    }
    else
    {
        throw new Exception::IndexOutOfBoundsException("StaticArray accessed at index greater than N.");
    }
}

template<typename T, unsigned int N>
StaticArray<T, N>& StaticArray<T, N>::operator = (const StaticArray<T,N>& other)
{
    for (unsigned int i = 0; i < N; i++)
    {
        this->_data[i] = other._data[i];
    }
    return *this;
}

main.cpp

#include "StaticArray.h"
#include "Array.h"

int main(int argc, char** argv[])
{
    StaticArray<int,5> sar;

    sar[0] = new int(1);
    sar[1] = new int(2);
    sar[2] = new int(3);
    sar[3] = new int(4);
    sar[4] = new int(5);

    return 0;
}

Solution

  • You don't have to have a definition of class Array to use class StaticArray except at the point you actually call ToArray. So it doesn't matter in which order the templates and their functions are declared, just as long as each one forward-declares the classes it uses.