2009-11-13 4 views
-3
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 являетсяC++ шаблонный класс не связывает

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 

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

+0

Dupe? http://stackoverflow.com/questions/1724036/splitting-templated-c-classes-into-hpp-cpp-files-is-it-possible/1724265#1724265 –

ответ

3

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

7

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

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

Примечание:

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

1

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

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

1

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

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

1

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

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

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

Смежные вопросы