Шаблонный класс C ++ не связывает - PullRequest
0 голосов
/ 13 ноября 2009
template<typename AT>
class growVector {

        int size;
        AT **arr;
        AT* defaultVal;

    public:

        growVector(int size , AT* defaultVal);   //Expects number of elements (5) and default value (NULL)
        AT*& operator[](unsigned pos);
        int length();
        void reset(int pos);    //Resets an element to default value
        void reset();           //Resets all elements to default value
        ~growVector();
};

и .cpp

template<typename AT>
growVector<AT>::growVector(int size, AT* defaultVal) {
    arr = new AT*[size];
    this->size = size;
    for (int i = 0 ; i < size; i++){
        arr[i] = defaultVal;
    }
}

template<typename AT>
AT*& growVector<AT>::operator [](unsigned pos){
    if (pos >= size){
        int newSize = size*2;
        AT** newArr = new AT*[newSize];
        memcpy(newArr, arr, sizeof(AT)*size);
        for (int i = size; i<newSize; i++)
            newArr[i] = defaultVal;
        size = newSize;
        delete arr;
        arr = newArr;
    }
    return arr[pos];
}

//template<typename AT>
//const AT*& growVector<AT>::operator [](unsigned pos) const{
//  if (pos >= size)
//      throw std::range_error("index out of range in constant vector");
//  }
//  return NULL;
//}
template<typename AT>
int growVector<AT>::length(){
    return size;
}

template<typename AT>
growVector<AT>::~growVector(){
    delete arr;
}

template<typename AT>
void growVector<AT>::reset(int pos){
    if (pos>=size)
        throw new std::range_error("index out of bounds");
    arr[pos] = defaultVal;
}

template<typename AT>
void growVector<AT>::reset(){
    for (int pos = 0; pos<size; pos++)
        arr[pos] = defaultVal;
}

... очень простой.

Я использую это в

int main() {

    growVector<char> gv(5, (char*)NULL);
    char* x = NULL;
    for (int i = 0; i< 50; i++){
        gv[i] = x;
    }
    gv.reset();
    return 0;
}

компилируется, но компоновщик говорит:

Invoking: GCC C++ Linker
g++ -pthread -o"base"  ./src/base.o  ./src/base/baseController.o ./src/base/baseThreads.o ./src/base/utils.o  ./src/base/utils/utilClasses.o   
./src/base.o: In function `main':
/home/dario/workspace/base/Debug/../src/base.cpp:95: undefined reference to `baseUtils::growVector<char>::growVector(int, char*)'
/home/dario/workspace/base/Debug/../src/base.cpp:98: undefined reference to `baseUtils::growVector<char>::operator[](unsigned int)'
/home/dario/workspace/base/Debug/../src/base.cpp:100: undefined reference to `baseUtils::growVector<char>::reset()'
/home/dario/workspace/base/Debug/../src/base.cpp:101: undefined reference to `baseUtils::growVector<char>::~growVector()'
/home/dario/workspace/base/Debug/../src/base.cpp:101: undefined reference to `baseUtils::growVector<char>::~growVector()'
collect2: ld returned 1 exit status

Я действительно невежественен

Ответы [ 5 ]

7 голосов
/ 13 ноября 2009

Как правило, для шаблонов определение должно быть помещено в заголовочный файл, поскольку оно требуется для всех модулей компиляции.

Существуют приемы, позволяющие избежать этого, когда вы знаете, с какими типами будет вызываться ваш шаблонный класс, но для действительно общих проблем он просто не работает.

Примечание

Если бы я был на вашем месте, я бы использовал контейнер STL, результат с меньшей вероятностью будет ошибочным.

3 голосов
/ 13 ноября 2009

Попробуйте также поместить определение в заголовочный файл. Для получения подробной информации, вы можете прочитать этот FAQ .

1 голос
/ 13 ноября 2009

Вы не указали ссылку на пространство имен baseUtils?

/home/dario/workspace/base/Debug/../src/base.cpp:95: undefined reference to `baseUtils::growVector<char>::growVector(int, char*)'

Я не видел его в вашем коде main (), и определение вашего класса не наследуется ни от какого другого класса.

1 голос
/ 13 ноября 2009

Компилятор должен видеть и объявление, и определение для создания экземпляра шаблона. Так как вы предоставили явную реализацию / специализацию growVector в .cpp, компилятор не сможет сгенерировать созданный вами экземпляр. Это одна из основных причин, по которой вы обнаружите, что классы шаблонов обычно объявляются и определяются в области заголовочного файла.

Обычно вы можете рассчитывать на то, что современный компоновщик достаточно умен, чтобы удалять дублирующиеся экземпляры одного и того же шаблона, но они не обязательно способны создавать экземпляры шаблонов.

1 голос
/ 13 ноября 2009

Короткая история: вам нужно поместить всю реализацию шаблона в шапку.

Теоретически, в C ++ есть ключевое слово («экспорт»), которое позволяет вам разделять шаблоны примерно так же, как и другой код (объявления в заголовке, тела в файле .cpp). К сожалению, есть только один компилятор (Comeau C ++), который реализует ключевое слово экспорта, поэтому этот параметр недоступен для большинства людей. Я полагаю, что если вы используете недокументированный переключатель или два, Intel C ++ также реализует ключевое слово export в некоторой степени, но оно не поддерживается, поэтому может возникнуть вопрос, действительно ли оно работает надежно или нет (я уверен, что синтаксический анализ , но я не удивлюсь, если у других деталей возникли проблемы).

...