C++ 为什么在使用模板时会出现“未解析的外部符号”错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/456713/
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 15:27:35  来源:igfitidea点击:

Why do I get "unresolved external symbol" errors when using templates?

c++templateslinker

提问by dlanod

When I write C++ code for a class using templates and split the code between a source (CPP) file and a header (H) file, I get a whole lot of "unresolved external symbol" errors when it comes to linking the final executible, despite the object file being correctly built and included in the linking. What's happening here, and how can I fix it?

当我使用模板为类编写 C++ 代码并在源 (CPP) 文件和头 (H) 文件之间拆分代码时,在链接最终可执行文件时,我会收到大量“未解析的外部符号”错误,尽管目标文件被正确构建并包含在链接中。这里发生了什么,我该如何解决?

回答by dlanod

Templated classes and functions are not instantiated until they are used, typically in a separate .cpp file (e.g. the program source). When the template is used, the compiler needs the full code for that function to be able to build the correct function with the appropriate type. However, in this case the code for that function is detailed in the template's source file and hence unavailable.

模板化的类和函数在使用之前不会被实例化,通常在单独的 .cpp 文件中(例如程序源)。使用模板时,编译器需要该函数的完整代码才能使用适当的类型构建正确的函数。但是,在这种情况下,该函数的代码在模板的源文件中有详细说明,因此不可用。

As a result of all this the compiler just assumes that it's defined elsewhere and only inserts the call to the templated function. When it comes to compile the template's source file, the specific template type that is being used in the program source isn't used there so it still won't generate the code required for the function. This results in the unresolved external symbol.

由于所有这些,编译器只是假设它是在别处定义的,并且只插入对模板化函数的调用。在编译模板的源文件时,程序源中使用的特定模板类型并未在那里使用,因此它仍然不会生成函数所需的代码。这导致未解析的外部符号。

The solutions available for this are to:

可用的解决方案是:

  1. include the full definition of the member function in the template's header file and not have a source file for the template,
  2. define all the member functions in the template's source file as "inline" (Update: [this does not work on Visual Studio 2017+]), or
  3. define the member functions in the template's source with the "export" keyword. Unfortunately this isn't supported by a lot of compilers.(Update: this has been removed from the standard as of C++11.)
  1. 在模板的头文件中包含成员函数的完整定义,并且没有模板的源文件,
  2. 将模板源文件中的所有成员函数定义为“内联”(更新:[这不适用于 Visual Studio 2017+]),或
  3. 使用“export”关键字定义模板源中的成员函数。不幸的是,很多编译器都不支持这一点。(更新:从 C++11 开始,这已从标准中删除。)

Both 1 and 2 basically address the problem by giving the compiler access to the full code for the templated function when it is attempting to build the typed function in the program source.

1 和 2 基本上都解决了这个问题,当编译器试图在程序源中构建类型化函数时,它允许编译器访问模板化函数的完整代码。

回答by shoosh

Another option is to put the code in the cpp file and in the same cpp file add explicit instantiations of the template with the types you expect to be using. This is useful if you know you're only going to be using it for a couple of types you know in advance.

另一种选择是将代码放在 cpp 文件中,并在同一个 cpp 文件中使用您希望使用的类型添加模板的显式实例。如果您知道您只会将它用于您事先知道的几种类型,这将非常有用。

回答by totem_motorist

For each file that include the .h file you should be to insert both lines:

对于包含 .h 文件的每个文件,您应该插入两行:

#include "MyfileWithTemplatesDeclaration.h"
#include "MyfileWithTemplatesDefinition.cpp"


sample

样本

#include "list.h"
    #include "list.cpp" //<---for to fix bug link err 2019



    int main(int argc, _TCHAR* argv[])
    {
        list<int> my_list;
        my_list.add_end(3);
    .
    .
    } 

also, you dont forget to place your declaration class among centinel constants

此外,您不要忘记将声明类放在 centinel 常量中

#ifndef LIST_H
#define LIST_H
#include <iostream>
.
.
template <class T>
class list
{
private:
    int m_size,
        m_count_nodes;
    T m_line;
    node<T> *m_head;
public:
    list(void);
    ~list(void);
    void add_end(T);
    void print();
};
#endif