Byz*_*ian 5 c++ templates header compilation-time explicit-instantiation
将源文件用于基于模板的类(STL和boost)以及将实现放入标头似乎是一种常见的惯例.我假设与头文件和源文件中的声明和实现之间的经典分离相比,这将增加编译包含头文件的源文件所需的时间.这样做的原因可能是因为您必须告诉源文件中的编译器使用哪些模板,这可能会导致文件膨胀.a文件.
假设链接器在库增长时也需要更多时间,那么编译包含库头的源文件所需的时间会更快?
1.不使用.cpp文件并将整个类(包括实现)放入标头中
//foo.hpp
template <class T>
class Foo
{
public:
Foo(){};
T bar()
{
T* t = NULL;
//do stuff
return *t;
}
};
Run Code Online (Sandbox Code Playgroud)
要么
2.在库本身的源文件中显式编译各种类型的模板
//foo.h
template <class T>
class Foo
{
public:
Foo(){};
T bar();
};
//foo.cpp
template <class T>
T Foo<T>::bar()
{
T* t = NULL;
//do stuff
return *t;
}
template class Foo<int>;
template class Foo<float>;
template class Foo<double>;
template class Foo<long long>;
Run Code Online (Sandbox Code Playgroud)
模板的关键问题是编译器不知道模板将用于哪些模板参数。编译器唯一知道模板与一组特定参数一起使用的情况是当它看到所使用的模板时,编译器将在此时实例化该模板。因此,代码通常被放入标头中,以便编译器可以在使用模板时代表用户实例化模板。
或者,模板的作者可以告诉编译器模板与特定的模板参数列表一起使用,并且只需显式实例化它们即可。在这种情况下,模板定义可以进入源文件(或者更可能的是,用户通常不包含的特殊标头)。这种方法的问题在于模板代码的作者不一定知道需要哪些实例化。
在 C++ 2011 中,还有一个中间立场:可以通过将特化声明为 来告诉编译器某些实例化已经创建extern
。这样,编译器知道它不需要使用某些参数实例化模板,但如果使用其他参数,它知道需要创建它们。例如,标准 C++ 库具有std::basic_string
并且它可以预测 和 的实例化char
可能wchar_t
会被使用,并且可以将它们放入库中,将实例化声明为extern
。然而,让代码易于使用使得可以std::basic_string<user_type>
与用户定义的类型一起使用。
展望未来,我们希望获得一个模块系统,但现在没有人真正知道这样的系统应该如何真正工作。对这个主题感兴趣的编译器实现者有一个小组来考虑模块,这样的系统很可能有助于缩短模板的编译时间。