您不能像这样转发声明类的“部分”。即使可以,您仍然需要在某处实例化代码,以便您可以链接它。有一些方法可以处理它,你可以让自己成为一个带有公共容器(例如vector)实例化的小库并将它们链接起来。然后你只需要编译一次,例如vector<int>。要实现这一点,您需要使用类似的东西-fno-implicit-templates
,至少假设您坚持使用 g++ 并使用template class std::vector<int>
所以,一个真实的工作示例。这里我有 2 个文件,a.cpp 和 b.cpp
一个.cpp:
#include <vector> // still need to know the interface
#include <cstdlib>
int main(int argc, char **argv) {
std::vector<int>* vec = new std::vector<int>();
vec->push_back(3);
delete vec;
return EXIT_SUCCESS;
}
所以现在我可以编译 a.cpp 了-fno-implicit-templates
:
g++ -fno-implicit-templates -c a.cpp
这会给我 ao 如果我然后我尝试链接 ao 我得到:
g++ a.o
/usr/bin/ld: Undefined symbols:
std::vector<int, std::allocator<int> >::_M_insert_aux(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&)
void std::_Destroy<int*, std::allocator<int> >(int*, int*, std::allocator<int>)
collect2: ld returned 1 exit status
不好。所以我们转向b.cpp:
#include <vector>
template class std::vector<int>;
template void std::_Destroy(int*,int*, std::allocator<int>);
template void std::__uninitialized_fill_n_a(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&, std::allocator<int>);
template void std::__uninitialized_fill_n_a(int*, unsigned long, int const&, std::allocator<int>);
template void std::fill(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&);
template __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > std::fill_n(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, unsigned long, int const&);
template int* std::fill_n(int*, unsigned long, int const&);
template void std::_Destroy(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, std::allocator<int>);
现在你对自己说,所有这些额外的模板东西是从哪里来的?我看到了template class std::vector<int>
,那很好,但是其余的呢?简短的回答是,这些东西的实现必然有点混乱,当你手动实例化它们时,这些混乱的一部分会泄露出来。您可能想知道我是如何弄清楚我需要实例化什么的。好吧,我使用了链接器错误;)。
所以现在我们编译 b.cpp
g++ -fno-implicit-templates -c b.cpp
我们得到 bo 连接 ao 和 bo 我们可以得到
g++ a.o b.o
万岁,没有链接器错误。
因此,要了解有关您更新的问题的一些详细信息,如果这是一门自酿课程,则不一定要如此混乱。例如,您可以将接口与实现分开,例如,除了 a.cpp 和 b.cpp 之外,我们还有 ch、c.cpp
ch
template<typename T>
class MyExample {
T m_t;
MyExample(const T& t);
T get();
void set(const T& t);
};
cpp
template<typename T>
MyExample<T>::MyExample(const T& t) : m_t(t) {}
template<typename T>
T MyExample<T>::get() { return m_t; }
template<typename T>
void MyExample<T>::set(const T& t) { m_t = t; }
a.cpp
#include "c.h" // only need interface
#include <iostream>
int main() {
MyExample<int> x(10);
std::cout << x.get() << std::endl;
x.set( 9 );
std::cout << x.get() << std::endl;
return EXIT_SUCCESS;
}
b.cpp,“库”:
#include "c.h" // need interface
#include "c.cpp" // need implementation to actually instantiate it
template class MyExample<int>;
现在您将 b.cpp 编译为 bo 一次。当 a.cpp 更改时,您只需要重新编译它并链接到 bo