سؤال

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;
}
هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

Explicit template instantiation. Add this line to the bottom of StaticArray.cpp:

template class StaticArray<int,5>;

I see the forward declaration for class Array at the beginning of StaticArray.h. In your main.cpp try swapping the lines to

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

from a quick glance it seems like the compiler hasnt seen Array when its building StaticArray and hence unresolved external?

I eventually managed to figure out the best way to make this functionality work in a structured manner.

You need to remove the conversions (such as StaticArray to Array) from the StaticArray class and instead have both StaticArray and Array included in another code file that contains utility functions (such as conversions).

The key here is to keep the includes working upwards. That is: utility.h (for example) includes Array.h and StaticArray.h instead of them including one another.

Then you are free to put all definition code into the StaticArray.h file with no cross-include side-effects (and thus fix the unresolved external).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top