我知道模板定义应该放在头文件中。这是否意味着模板使用的所有类的定义(直接或间接)也需要放在头文件中?
我有一个模板,它依赖于很多类,因此必须将它们全部放在头文件中,否则我将得到“错误LNK2019:未解析的外部符号”。在代码组织方面是否有更好的解决方案?
示例:
double inline MainFunction(double price, const Params& params)
{
Price<ModeEnum::NORMAL> pricer(price);
MethodOne<ModeEnum::NORMAL> methodOne;
return pricer.func(methodOne, params) ;
}
template<ModelEnum::Enum Mode>
struct Price
{
double price;
typedef double return_type;
Price(double price_) : price(price_){}
template<typename T> double func(const T& method, const Params& params) const
{
const typename T::PriceFactor factor(params);
return factor ..... ;
}
};
T :: PriceFactor实际上是B类,它是tempalte MethodOne中定义的类型定义。因此,我必须将类B的构造函数和所有(很多)函数和类放在头文件中。
答案 0 :(得分:2)
简单的答案是:当模板被实例化时,编译器需要看到所有代码。如果代码不可见,编译器将不会执行实例化,您需要提供显式实例化。显式实例化是否可行取决于模板的性质:
std::vector<T>
这样的模板可能希望完全在标头中实现。您可以将声明和函数模板的定义分开,但将部分放入不同的文件中没有多大意义。std::basic_ostream<cT>
,char
,wchar_t
实例化,可能在某些时候char16_t
和char32_t
可能希望在标题中声明并在另一个标题中定义,该标题自动包含 not 。相反,带有定义的标头仅包含在明确实例化类模板的特殊实例化文件中。std::complex<T>
的情况,可以使用float
,double
和long double
进行实例化。对于像这样的模板,标题只包含声明,定义将进入合适的翻译单元。当上面提到代码将放入源文件时,显然只适用于非平凡的代码:出于性能原因,简单的转发函数可能应该保留inline
函数。但是,这些往往不是引起大量依赖的有趣函数模板。
有关如何整理模板代码的更全面的说明,请参阅此blog entry。
答案 1 :(得分:0)
如果简单,我只需将其全部放在一个标题中:
//simple_template.h
#ifndef SIMPLE_TEMPLATE_H
#define SIMPLE_TEMPLATE_H
template <typename T>
class SomethingSimple
{
public:
T foo() { return T();}
};
#endif
如果它更复杂,我创建一个“内联标题”(并使用谷歌样式指南中的命名约定)来获取:
//complicated_template.h
#ifndef COMPLICATED_TEMPLATE_H
#define COMPLICATED_TEMPLATE_H
template <typename T>
class SomethingComplicated
{
public:
T foo();
};
#include "compilcated_template-inl.h"
#endif
//compilcated_template-inl.h
#ifndef COMPLICATED_TEMPLATE_INL_H
#define COMPLICATED_TEMPLATE_INL_H
#include "complicated_template.h"
template <typename T>
T SomethingComplicated<T>::foo() {/*lots of code here*/; return T();}
#endif
这样,complex_template.h非常易读,但使用该模板的任何人都可以包含该标题。例如,
//uses_template.h
#ifndef USES_TEMPLATE_H
#define USES_TEMPLATE_H
#include "complicated_template.h"
class something_using_complicated
{
private:
SomethingComplicated<int> something_;
};
注意:如果使用该模板的类也是模板类,那么您将使用仅限标头库。这就是为什么BOOST主要是标题。