2009-11-13 60 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()代码中看到它,并且你的类定义没有从任何其他类继承。