2009-11-13 58 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 – 2009-11-13 14:41:41

回答

3

試着將定義在頭文件了。詳情請參閱this FAQ

7

對於模板,一般來說,定義應該放在頭文件中,因爲它是所有編譯單元都需要的。

當你知道哪些類型的模板類將被調用時,有一些技巧可以避免這樣做,但對於真正普遍的問題,它只是不起作用。

注意

如果我是你,我會用一個STL容器,結果是不太可能被馬車。

1

小故事:您需要將模板的整個實現放在標題中。從理論上講,C++有一個關鍵字(「導出」),它允許你像其他代碼(頭文件中的聲明,.cpp文件中的實體)那樣分開模板。不幸的是,只有一個編譯器(Comeau C++)實現了export關鍵字,所以這個選項不適用於大多數人。我相信如果你使用一個或兩個未公開的開關,Intel C++在某種程度上也實現了export關鍵字,但它不被支持,所以它可能是開放的問題,它是否真的可靠地工作或不(我確定解析部分,但如果其他部件有問題,我不會感到驚訝)。

1

編譯器需要同時看到聲明和定義才能實例化模板。正如您在.cpp中提供了growVector的顯式實例化/專業化一樣,編譯器無法爲您生成實例化模板。這是你會發現模板類傾向於在頭文件範圍內聲明和定義的主要原因之一。

您通常可以依賴現代鏈接器來足夠聰明以移除同一模板的重複實例,但它們不一定能夠實例化模板。

1

您是否遺漏了對baseUtils命名空間的引用?

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

我沒有在你的main()代碼中看到它,並且你的類定義沒有從任何其他類繼承。