我有结构来定义一个点:
struct point_d
{
double x;
double y;
};
和
struct point_f
{
float x;
float y;
};
并且有一个将点数组写入文件的方法,该方法是静态的并且在 export_to_file 类中。
h文件中的方法描述:
template<typename T>
static void save_to_bln_contour(deque<T> points, const int type_contour, const string filename);
cpp文件中的方法:
template<typename T>
export_to_file::save_to_bln_contour(deque<T> points, const int type_contour, const string filename)
{
/**/
}
我这样调用方法:
export_to_file::save_to_bln_contour<point_d>(points, 1, "test1");
如果此方法包含在我调用它的同一类中,则没有错误。怎么了?
如果我按上述方式编写,那么工作室链接器会发誓错误代码 LNK2019:
"public: static void __cdecl export_to_file::save_to_bln_contour(class std::deque >,int,class std::basic_string,class std::allocator >)" (?? $save_to_bln_contour@Upoint_d@@@export_to_file@@SAXV?$ deque@Upoint_d@@V?$allocator@Upoint_d@@@std@@@std@@HV?$basic_string@DU?$char_traits@D@std@@V ?$allocator@D@2@@2@@Z ) 和 "public: void __cdecl surface_fault::get_points_intersect(class surface_res &,class fault *)" (?get_points_intersect@surface_fault@@QEAAXAEAVsurface_res@@PEAVfault@@@Z) GRD_MBA E:\Projects\GRD_MBA\GRD_MBA\surface_fault.obj 1
工作室中的编码存在问题。
我需要为 point_d 结构和 point_f 结构的点调用save_to_bln_contour方法。
将模板实现移动到头文件,或在“.cpp 文件”中使用给定的一组参数实例化模板。
下面的情况说明。它是用的
gcc,不是cl,但意思是一样的。本质很简单——不同的翻译单元彼此不了解。编译器生成代码并将其提供给链接器,然后链接器决定从哪里获取哪些定义。让我们采用一个非模板函数(为简单起见):让我们编译
main.cpp: g++ main.cpp -c -o main.o收到一个文件
main.o。如您所见,没有错误(-c 开关只是“告诉”编译器您只需要编译成一个对象,无需调用链接器)。在这种情况下,编译器只需要声明即可汇编。
让我们编译第二个文件:
g++ func.cpp -c -o func.o这里一切都很好。现在让我们把它们放在一起。我们也将使用它
g++,他自己知道如何调用链接器(以免糊弄他的脑袋ld)。g++ -o main main.o func.o一切都聚集了。我们开始:
./main一切都很好,一切正常。现在让
main.cpp我们像这样改变它:让我们编译
main.cpp:g++ -c -o main.o main.cpp让我们把它变成一个二进制文件:
g++ -o main main.o func.o一切都很好。但是我们没有
func.cpp再次编译。我们只是编译main.cpp然后与现有的func.o. 也就是说,我们没有花费 100,500 小时来构建其他库,因为我们更改了main.cpp. 我们只编译更改的部分就足够了。现在大约
undefined reference。让我们取相同的文件并尝试以这种方式编译:g++ -o main main.cpp收到
undefined reference。为什么?问题是编译时,编译器main.cpp有一个声明foo,它足以检查这个名字的正确使用foo。链接器将查找此 foo 所在的位置。但是链接器也不知道在哪里foo寻找它,因为我们没有将他指向func.o. 因此,它告诉我们发生了这样那样的错误。如果我们告诉他 func.o,那么一切都会好起来的:g++ -o main main.cpp func.o同时,请注意,
func.cpp一般来说,它在我们的任何地方都不再被照亮。Bfunc.o有我们需要的函数定义foo,所以链接器可以找到它。现在到模板。
首先考虑我们没有的情况
func.cpp:收集:
g++ -o main main.cpp一切都很好。
在这种情况下,foo 不是一个函数,它是一个函数模板。
根据这种模式,编译器可以构建代码。
使用时
foo:foo<int>();编译器根据给定的模板(实例化)生成函数代码,其中T是 typeint。对于foo<double>();- 同样,只有T-double。现在让我们func.cpp在那里添加和移动实现foo:收集:
g++ -o main main.cpp并得到
undefined reference。为什么?因为我们有声明
foo,但没有定义,所以编译器无法实例化函数(根据模板生成),编译器只匹配了使用--一切正常,把对象交给链接器,链接器找不到执行,因为他不知道它在哪里搜索。好的,让我们这样做:g++ -o main main.cpp func.cpp又一次
undefined reference。毕竟,为什么我们指出了实现的位置?现在,这就是单独编译再次发挥作用的地方。
main.cpp也编译func.cpp了。他们对彼此一无所知。在main.cpp使用foo中,但func.cpp实际上没有这个模板的实例。为什么不存在?它func.cpp没有在任何地方使用,因此编译器没有实例化模板。也就是说,如果不使用具有特定模板参数集的模板,则编译器将不会为具有给定模板参数集的模板生成代码。怎样成为?让我们“强制”编译器func.cpp生成代码。如何?就在我们使用的某个地方foo<тип>,例如:我们收集:
g++ -o main main.cpp func.cpp一切都已组装并正常工作。为什么?
func.cpp出现bar了一个使用foo<int>and的函数foo<double>,并且在这个翻译单元中有一个模板定义,这意味着编译器将实例化模板,现在func.cpp里面有必要的定义,链接器可以找到它们。那些。任务完成 - 我们已经强制编译器实例化模板。但是为此我们不得不使用另一个非模板函数。但是有一个更合适的解决方案——显式实例化。显式实例化导致编译器使用给定的参数集实例化模板。让我们改变func.cpp我们收集:
g++ -o main main.cpp func.cpp一切都很好,一切都组装好了。但是,值得添加到 main 中,例如
foo<char>();,我们将如何再次获得undefined reference,因为我们的编译器没有为这组参数 (char) 生成代码。也就是说,我们可以将模板的实现移动到.cpp,但在这种情况下,我们需要以某种方式实例化模板以获得必要的参数集。我的帖子原文:http ://www.cyberforum.ru/cpp-beginners/thread1798717.html#post9488987