为什么这个模板示例代码没有编译?

use*_*232 1 c++ templates lnk2019

我想尝试使用模板来学习如何使用它们.我在Visual Studio 2010 C++中创建了一个包含三个文件的项目:

Controller.cpp:

#include <iostream>

#include "Foo.h"

using namespace std;

int main(){

    Example<int,string> example;

    example.appols(5, "Hi");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

foo.h中:

#include <iostream> 

using namespace std;

template <class T, class E>
class Foo{
public:
    void printThis(T t, E e);
};

template <class T, class E>
class Example{
public:
    void appols(T t, E e);
};
Run Code Online (Sandbox Code Playgroud)

Foo.ipp:

#include <iostream>

#include "Foo.h"

using namespace std;

template<class T, class E>
void Foo<T, E>::printThis(T t, E e){
    cout << "FOO! " << t << ' ' << e << endl;
}

template<class T, class E>
void Example<T, E>::appols(T t, E e){
    cout << "APPOLS!! " << t << ' ' << e << endl;
    Foo<T,E> f;
    f.printThis(t,e);
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译时,我得到:

1>------ Build started: Project: Template Practive, Configuration: Debug Win32 ------
1>Controller.obj : error LNK2019: unresolved external symbol "public: void __thiscall Example<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::appols(int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?appols@?$Example@HV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function _main
1>C:\Users\Matthew\documents\visual studio 2010\Projects\Template Practive\Debug\Template Practive.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Run Code Online (Sandbox Code Playgroud)

你能帮我看看我在这里做错了什么error LNK2019,来自哪里?先感谢您!

Mr.*_*C64 5

解密错误消息

让我们先尝试解码错误信息:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > >::appols(int,class
std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)"
(?appols@?$Example@HV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 
referenced in function _main
Run Code Online (Sandbox Code Playgroud)

我们可以在此错误消息中开始降低噪声/信号比.

这部分(?appols@?$Example@HV?$basic_string@DU?$char_traits@D@std@@...只是C++ 名称修改.它适用于C++编译器,并不是人类可读的东西.所以我们可以放弃它.

简化的错误消息变为:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > >::appols(int,class
std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)"
referenced in function _main
Run Code Online (Sandbox Code Playgroud)

第一行告诉我们有一个"未解决的外部符号".让我们尝试识别它,看下一行.

部分:

class std::basic_string<char,struct std::char_traits<char>...
Run Code Online (Sandbox Code Playgroud)

只是长名称std::string(对应于std::basic_string具有char字符类型的模板并使用默认char特征和默认分配器).

因此,我们可以进一步减少噪音,std::string代替那些冗长的部分:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,string>::appols(int,string)"
referenced in function _main
Run Code Online (Sandbox Code Playgroud)

现在错误更加清晰.

__thiscall部分只是默认情况下在C++成员函数上使用的调用约定.

所以,链接器抱怨这个方法:

"public: void Example<int,string>::appols(int,string)"
Run Code Online (Sandbox Code Playgroud)

对应于你的Example<T,E>::appols():

template <class T, class E>
class Example{
public:
    void appols(T t, E e);
};
Run Code Online (Sandbox Code Playgroud)

何时T=intE=std::string.

这与您main()在Controller.cpp 中的函数相对应:

Example<int,string> example;

example.appols(5, "Hi");
Run Code Online (Sandbox Code Playgroud)

问题的诊断和解决方案

问题是所有模板源代码必须在头文件中,而不是在.cpp文件中.

实际上,编译器需要定义模板代码才能实例化它.

因此,您可以将代码从Foo.ipp文件移动到Foo.h(或仅从#include "Foo.ipp"您的Foo.h),并添加inline到模板函数定义:

// New code in Foo.h

template<class T, class E>
inline void Foo<T, E>::printThis(T t, E e){
    cout << "FOO! " << t << ' ' << e << endl;
}

template<class T, class E>
inline void Example<T, E>::appols(T t, E e){
    cout << "APPOLS!! " << t << ' ' << e << endl;
    Foo<T,E> f;
    f.printThis(t,e);
}
Run Code Online (Sandbox Code Playgroud)

另请注意,using namespace std;在头文件中非常糟糕,因为这会污染包含头的所有客户端的全局命名空间.只需使用std::明确的前缀头文件(如:std::cout,std::endl等).