模板问题导致连接错误(C ++)(Template issue causes linker erro

2019-09-02 02:01发布

我有很少的想法发生了什么事在关于C ++模板,但我想实现的是搜索满足给定属性的元素的矢量(在这种情况下,寻找一个给定的名称)的功能。 我在我的.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

同样,我是新来的模板,所以我不知道发生了什么事。 我已经通过谷歌找到的LNK2019所有实例已经对没有使用正确的库,但因为这是我自己的功能我不明白为什么这会发生。

此外,一个相关的问题:有没有办法让一个模板参数,以便它必须是某一类的子类,即模板?

Answer 1:

你必须有可用的主叫网站模板定义。 这意味着没有.cpp文件。

原因是模板不能编译。 想想功能饼干,编译器是一个烤箱。

模板只是一个俗套,因为他们不知道自己是什么类型的cookie。 它只是告诉编译器如何使函数给出一个类型时,但其本身,它不能被使用,因为有被操作上没有具体类型。 你可以不会做饭一个俗套。 只有当你有美味的饼干面团准备(即给定的编译器面团[类型])),你可以切饼干和做饭。

同样,只有当你实际使用的模板与某些类型可以使编译器生成的实际功能,并编译。 它不能做到这一点,但是,如果模板定义丢失。 你必须把它移到头文件,所以函数的调用者可以使饼干。



Answer 2:

你可能从缺少一个有效的实例化的痛苦。 如果你把你的模板定义在一个单独的.cpp文件,当编译器编译该文件可能不知道哪个实例需要。 相反,在这将实例化模板函数的正确版本的调用点,如果函数体的定义不可用,编译器不会有信息来实例化所需要的专业。

你有两个选择。 把函数体在头文件中的函数模板。

例如,在头文件中:

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);


Answer 3:

这里的答案是伟大的。

我只想补充一点,这就是为什么经常在除.h.cpp在一个项目文件。 你会经常发现.inl文件。 该模板定义将进入.inl文件。

这些.inl文件意味着内联,并且通常由包括.h在文件的底部,所有的头声明之后相同名称前缀的文件。 这实际上使他们的头文件中的一部分,但是分离任何定义的声明。

由于它们是荣耀的头文件,你应该采取一切必要的防范措施,你会用一个普通的头文件,即包括警卫等。



Answer 4:

偶然发现了同样的问题,发现这其中指出3个解决方法: http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-ah-file-and-imp

其中是创建在.cpp文件中“虚拟”的方法,调用与不同类型的模板/类功能容易。 从链接粘贴:

// No need to call this TemporaryFunction() function, it's just to avoid link error.
void TemporaryFunction ()
{
    TestTemp<int> TempObj;
    TestTemp<float> TempObj2;
}


Answer 5:

我只注意到你有这似乎是一个悬而未决的第二个问题:

有没有一种方法,使一个模板参数,以便它必须是某一类的子类,即模板?

有可能的。 例如,看到is_base_of在Boost.TypeTraits 。

不过,我很好奇:为什么你要吗? 通常情况下,它的参数模板的要求是不是在参数的类型本身,而是在其涉及该类型的表达式是合法的。 例如,假设您有:

template<class T>
void foo(const T& t)
{
    if (t.foo()){
       t.bar("blah");
    }
}

话说T必须从像继承:

class HasFooAndBar
{
public:
  void foo()const;
  void bar(const char*)const;
};

带来什么,因为功能的实例无论如何都会失败,如果该类型不支持的操作。 此外,它限制了不必要的适用性foo() 事实上,Foo的任何要求是t.foo() and t.bar(const char*)是一个常数T.例如有效的表达,这种类型不从HasFooAndBar继承和仍然是有效的FOO()参数:

struct DifferentFromHasFooAndBar
{
  bool foo()const;
  std::string bar(const std::string&)const;
};


Answer 6:

你把你的模板函数定义在CPP文件? 然后将其移动到头部和内嵌了。



文章来源: Template issue causes linker error (C++)