模板问题导致链接器错误 (C++)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1639797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:41:57  来源:igfitidea点击:

Template issue causes linker error (C++)

c++templatescompiler-errors

提问by marsolk

I have very little idea what's going in regards to C++ templates, but I'm trying to implement a function that searches a vector for an element satisfying a given property (in this case, searching for one with the name given). My declaration in my .h file is as follows:

我对 C++ 模板的情况知之甚少,但我正在尝试实现一个函数,该函数在向量中搜索满足给定属性的元素(在这种情况下,搜索具有给定名称的元素)。我在 .h 文件中的声明如下:

template <typename T>
T* find_name(std::vector<T*> v, std::string name);

When I compile, I get this linker error when I call the function:

当我编译时,调用函数时出现此链接器错误:

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

Again, I'm new to templates so I don't know what's going. All instances I've found of LNK2019 through Google have been about not using the correct libraries, but since this is my own function I don't see why this would be happening.

同样,我是模板的新手,所以我不知道发生了什么。我通过 Google 发现的 LNK2019 的所有实例都是关于没有使用正确的库,但由于这是我自己的功能,我不明白为什么会发生这种情况。

Also, a related question: Is there a way to make a template parameter so that it has to be a subclass of a certain class, i.e. template?

另外,一个相关的问题:有没有办法让模板参数成为某个类的子类,即模板?

回答by GManNickG

You have to have your template definitions available at the calling site. That means no .cppfiles.

您必须在调用站点上提供模板定义。这意味着没有.cpp文件。

The reason is templates cannot be compiled. Think of functions as cookies, and the compiler is an oven.

原因是模板无法编译。把函数想象成饼干,而编译器就是一个烤箱。

Templates are only a cookie cutter, because they don't know what type of cookie they are. It only tells the compiler how to make the function when given a type, but in itself, it can't be used because there is no concrete type being operated on. You can't cook a cookie cutter. Only when you have the tasty cookie dough ready (i.e., given the compiler the dough [type])) can you cut the cookie and cook it.

模板只是一个饼干切割器,因为它们不知道它们是什么类型的饼干。它只告诉编译器在给定类型时如何制作函数,但它本身无法使用,因为没有具体的类型被操作。你不能做饼干刀。只有当你准备好美味的饼干面团时(即,给编译器面团 [类型]))你才能切割饼干并烹饪它。

Likewise, only when you actually use the template with a certain type can the compiler generate the actual function, and compile it. It can't do this, however, if the template definition is missing. You have to move it into the header file, so the caller of the function can make the cookie.

同样,只有当您实际使用某种类型的模板时,编译器才能生成实际的函数,并对其进行编译。但是,如果缺少模板定义,则无法执行此操作。您必须将其移动到头文件中,以便函数的调用者可以制作 cookie。

回答by CB Bailey

You are probably suffering from missing a valid instantiation. If you put your template definition in a separate .cpp file, when the compiler compiles that file it may not know which instantiations you need. Conversely, at the call sites which would instantiate the correct version of the template function, if the definition of the function body isn't available the compiler won't have the information to instantiate the required specializations.

您可能正因缺少有效的实例化而苦恼。如果您将模板定义放在单独的 .cpp 文件中,当编译器编译该文件时,它可能不知道您需要哪些实例化。相反,在将实例化模板函数的正确版本的调用点,如果函数体的定义不可用,编译器将没有信息来实例化所需的特化。

You have two options. Put the function body for the function template in the header file.

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

e.g. in the header file:

例如在头文件中:

template <typename T>
inline T* find_name(std::vector<T*> v, std::string name)
{
    // ...
}

or explicitly instantiate the template in the .cpp where you've defined the template.

或者在您定义模板的 .cpp 中显式实例化模板。

e.g. in the source file (will probably require #includeing the file that defines Item):

例如在源文件中(可能需要#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);

回答by chollida

The answers here are great.

这里的答案很棒。

I'll just add that this is often why in addition to .hand .cppfiles in a project. You'll often find .inlfiles. The template definitions will go into the .inlfile.

我只想补充一点,这通常是为什么在项目中添加.h.cpp文件的原因。你会经常找到.inl文件。模板定义将进入.inl文件。

These .inlfiles mean inline and will usually be included by the .hfile of the same name prefix at the bottom of the file after all the header declarations. This effectively makes them part of the header file but separates the declarations from any definitions.

这些.inl文件意味着内联,通常会被包含在.h文件底部的所有标头声明之后的同名前缀文件中。这有效地使它们成为头文件的一部分,但将声明与任何定义分开。

Since they are glorified header files you should take all the same precautions that you would with a regular header file, ie include guards etc.

由于它们是美化的头文件,因此您应该采取与常规头文件相同的所有预防措施,即包括保护等。

回答by KBog

Stumbled upon the same issue and found this which states 3 workarounds: http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-a-h-file-and-imp

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

Among them is an easy one where you create a "dummy" method in the .cpp file, that calls the template/class function with the different types. Pasted from the link:

其中有一个简单的方法,您可以在 .cpp 文件中创建一个“虚拟”方法,该方法调用具有不同类型的模板/类函数。从链接粘贴:

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

回答by éric Malenfant

I just noticed that you had a second question which seems to be unanswered:

我刚刚注意到你有第二个问题似乎没有答案:

Is there a way to make a template parameter so that it has to be a subclass of a certain class, i.e. template?

有没有办法让模板参数成为某个类的子类,即模板?

It is possible. For example, see is_base_ofin Boost.TypeTraits.

有可能的。例如,看到is_base_ofBoost.TypeTraits

However, I'm curious: Why do you want that? Normally, the requirements of a template on its parameters are not on the parameter's type itself, but on which expressions involving that type are legal. For example, imagine that you have:

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

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

Saying that T must inherit from something like:

说 T 必须从以下内容继承:

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

brings nothing because the instantiation of the function will fail anyway if the type does not support the operations. Moreover, it needlessly restricts the applicability of foo(). In fact, foo's any requirements are that t.foo()and t.bar(const char*)are valid expressions on a const T. For example, this type does not inherit from HasFooAndBar and is still a valid foo() parameter:

什么都不带来,因为如果类型不支持操作,函数的实例化无论如何都会失败。此外,它不必要地限制了 的适用性foo()。事实上,foo 的任何要求都是t.foo()and t.bar(const char*)const T 上的有效表达式。例如,此类型不继承自 HasFooAndBar 并且仍然是有效的 foo() 参数:

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

回答by dirkgently

Did you put your template function definition in a cpp file? Then move it to the header and inline it.

您是否将模板函数定义放在 cpp 文件中?然后将其移动到标题并内联它。