模板问题导致链接器错误(C ++)
我很less知道C ++模板是怎么回事,但我试图实现一个函数,它search一个满足给定属性的元素(在这种情况下,search给定的名称)的向量。 我的.h文件中的声明如下所示:
template <typename T> T* find_name(std::vector<T*> v, std::string name);
当我编译时,我得到这个链接器错误,当我调用该函数:
Error 1 error LNK2019: unresolved external symbol "class Item * __cdecl find_name<class Item>(class std::vector<class Item *,class std::allocator<class Item *> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$find_name@VItem@@@@YAPAVItem@@V?$vector@PAVItem@@V?$allocator@PAVItem@@@std@@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z) referenced in function "public: class Item * __thiscall Place::get_item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?get_item@Place@@QAEPAVItem@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) place.obj Program2
再次,我是新的模板,所以我不知道发生了什么事。 我通过Googlefind的所有LNK2019实例都没有使用正确的库,但是由于这是我自己的函数,我不明白为什么会这样。
另外,还有一个相关的问题:是否有一种方法来创build一个模板参数,以便它必须是某个类的子类,即模板?
您必须在呼叫站点提供您的模板定义。 这意味着没有.cpp
文件。
原因是模板无法编译。 把函数想象成cookies,编译器就是一个烤箱。
模板只是一个cookies,因为他们不知道它们是什么types的cookie。 它只告诉编译器如何在给定一个types的时候创build函数,但是它本身不能被使用,因为没有具体的types被操作。 你不能煮曲奇饼。 只有当你有美味的cookies面团准备好(即,给编译器的面团[types])),你可以切cookies和做饭。
同样,只有当你实际使用具有某种types的模板时,编译器才能生成实际的函数并编译它。 但是,如果缺less模板定义,则无法执行此操作。 您必须将其移动到头文件中,以便函数的调用者可以创buildcookie。
您可能正在错过一个有效的实例。 如果将模板定义放在单独的.cpp文件中,那么当编译器编译该文件时,可能不知道需要哪个实例。 相反,在实例化模板函数的正确版本的调用地点,如果函数体的定义不可用,则编译器将不具有实例化所需专业化的信息。
你有两个select。 将函数模板的函数体放在头文件中。
例如在头文件中:
template <typename T> inline T* find_name(std::vector<T*> v, std::string name) { // ... }
或者在您定义模板的.cpp中显式实例化模板。
例如在源文件中(可能需要#include
定义Item
的文件):
template <typename T> T* find_name(std::vector<T*> v, std::string name) { // ... } template Item* find_name<Item>(std::vector<Item*> v, std::string name);
这里的答案很好。
我只是补充说这通常是为什么除了项目中的.h
和.cpp
文件。 你会经常find.inl
文件。 模板定义将进入.inl
文件。
这些.inl
文件表示内联,并且在所有头声明之后,通常将被包含在文件底部的相同名称前缀的.h
文件中。 这有效地使它们成为头文件的一部分,但将声明与任何定义分开。
因为它们是荣耀的头文件,所以你应该采取与常规头文件相同的预防措施,即包括警卫等。
偶然发现了同样的问题,并发现这种状态3解决方法: http : //www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-ah-file-and-imp
其中一个简单的方法就是在.cpp文件中创build一个“虚拟”方法,它使用不同的types调用模板/类函数。 从链接粘贴:
// No need to call this TemporaryFunction() function, it's just to avoid link error. void TemporaryFunction () { TestTemp<int> TempObj; TestTemp<float> TempObj2; }
你把你的模板函数定义在一个cpp文件中吗? 然后将其移动到标题并将其内联。
我刚刚注意到你有第二个问题,似乎没有答案:
有没有办法做一个模板参数,以便它必须是某个类的子类,即模板?
有可能的。 例如,请参阅Boost.TypeTraits中的 is_base_of
。
不过,我很好奇:你为什么要这样? 通常,模板对其参数的要求不在参数的types本身上,而是涉及该types的expression式是合法的。 例如,假设你有:
template<class T> void foo(const T& t) { if (t.foo()){ t.bar("blah"); } }
说T必须inheritance下面的东西:
class HasFooAndBar { public: void foo()const; void bar(const char*)const; };
如果types不支持操作,那么函数的实例化将失败。 而且,它不必要地限制了foo()
的适用性。 实际上,foo的任何要求都是t.foo()
and t.bar(const char*)
是const T上的有效expression式。例如,这个types不能从HasFooAndBarinheritance,并且仍然是一个有效的foo()参数:
struct DifferentFromHasFooAndBar { bool foo()const; std::string bar(const std::string&)const; };