我有结构来定义一个点:
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