首页 > 编程语言 >为什么C++模板只能在头文件中实现

为什么C++模板只能在头文件中实现

时间:2024-07-24 16:55:19浏览次数:13  
标签:头文件 doSomething void C++ cpp Foo 模板

为什么C++模板只能在头文件中实现

答案:模板的实现并非必须在头文件中。

bug再现:当我尝试将模板的定义和实现分别保存在头文件(Foo.h)和实现文件(Foo.cpp)中时,程序在链接时报错:

错误	LNK2019	无法解析的外部符号 "public: void __cdecl Foo<int>::doSomething(int)" (?doSomething@?$Foo@H@@QEAAXH@Z),函数 main 中引用了该符号

以下是头文件和实现文件内容:

Foo.h

template <typename T>
struct Foo
{
 void doSomething(T param);   
}

Foo.cpp

template <typename T>
void Foo<T>::doSomething(T param){
    
}

以上代码出错的原因在于,当实例化一个模板时,编译器会根据给定的模板参数创建一个新类,对于上述代码,我们在main.cpp中对Foo进行实例化:

//main.cpp
int main(){
    Foo<int>f;
}

当读取到 Foo<int>f;这一行时,编译器将会创建一个新类(我们将其称为 FooInt),如下所示:

struct FooInt
{
    void doSomething(int param);
}

因此,编译器需要访问方法的实现,用模板参数(本例中是int)来实例化他们。如果这些实现没有在头文件中,它们将不可访问,导致编译器无法实例化模板。

通用的解决方法是在头文件中写模板的声明,然后实现类在实现文件中(.cpp),同时在头文件尾部将实现文件include进来。

Foo.h

template <typename T>
struct Foo
{
 void doSomething(T param);   
}
#include "Foo.cpp"

Foo.cpp

template <typename T>
void Foo<T>::doSomething(T param){
    
}

这个时候我们会遇到一个编译错误:错误 C2995 “void Foo<T>::doSomething(T)”: 函数模板已经定义

主要原因是在Foo.h头文件中包含了Foo.cpp执行文件,对成员函数进行了定义;而Foo.cpp执行文件又包含在项目中,再次对成员函数进行了定义,所以会有“函数模板已经定义”的错误信息。可以将模板类对应的Foo.cpp执行文件从项目中移除,注意是“移除”而不是“删除”。

这样的话,实现依然与声明分离,但是编译器可以正常访问它。

源码下载

C++ Super-FAQ on this subject

标签:头文件,doSomething,void,C++,cpp,Foo,模板
From: https://blog.csdn.net/ChuJian_cao/article/details/140663370

相关文章

  • C++ opencv putText
    C++opencv putText  #include<opencv2/opencv.hpp>intmain(){//创建一个空白图像cv::Matimg(400,400,CV_8UC3,cv::Scalar(255,255,255));//设置文本内容std::stringtext="Hello,OpenCV!";//设置文本起始坐标(左下角坐标)......
  • vue的侦听器/表单输入绑定和模板引用
    1.侦听器侦听器在修改数据过程中,实时的侦听数据,将修改前数据和修改后数据记录2.表单输入绑定在input标签中输入v-model指令可以实时的显示input标签中输入的内容,v-model.lazy指令为不实时显示,在input标签中输入的内容用鼠标点击空白页面或ENTER后显示3.模板引用直接读取DOM......
  • c++ 《小技巧》
    使用swap回收多余空间#include<vector>#include<iostream>usingnamespacestd;intmain(){vector<int>v;for(inti=0;i<100000;++i){v.push_back(i);}cout<<v.size()<<endl;//100000cout<......
  • C/C++ 建议编译选项
    本文介绍一些OI选手可能用到的编译选项。警告选项在程序设计中,我们可能不小心写出一些不合常理的代码语句。大部分情况下,这会使程序行为脱离我们的本意。使编译器发出警告可以在一定程度下规避这种情况。-Wall启动常见的警告选项,包括但不限于:未使用的变量、函数或标签未......
  • 易优CMS模板标签field字段值输出指定栏目ID的下级栏目的文档列表
    【基础用法】标签:field描述:获取channelartlist标签里的字段值,field标签只能在channelartlist标签里使用。用法:{eyou:channelartlisttypeid='栏目ID'type='son'row='20'}<ahref='{eyou:fieldname='typeurl'/}'>{eyou:fieldname='typen......
  • 易优CMS模板标签relevarticle相关文档
    [基础用法]标签:relevarticle描述:通过前3个TAG标签或前3个关键词,检索整站文档标题中含有tag标签或者关键词的相关文档,进行关联。在没有tag标签情况下,就以前3个关键词检索文档标题进行关联。这个标签随着数据量的增加可能会比较影响检索性能。提示:使用该标签之前,必须先安装相关文档......
  • 易优CMS模板标签uibackground背景图片在模板文件index.htm中调用uibackground标签,实现
    【基础用法】标签:uibackground描述:背景图片上传标签,使用时结合html一起才能完成可视化布局,只针对具有可视化功能的模板。用法:<divclass="eyou-edit"e-id="文件模板里唯一的数字ID"e-page='文件模板名'e-type="background"style="background-image:url({eyou:uibackgrounde......
  • C++ 打印菱形的程序(Program to print the Diamond Shape)
    给定一个数字n,编写一个程序来打印一个有2n行的菱形。例子:  //C++programtoprintdiamondshape//with2nrows #include<bits/stdc++.h>usingnamespacestd;//Printsdiamondpatternwith2nrows voidprintDiamond(intn) {   intspace=n......
  • 【简单易懂,复制可运行】C++通讯录管理系统实现增删改查
    自己写的300行c++通讯录管理系统,可以实现如下功能: 具体代码如下:#include<iostream>usingnamespacestd;#defineMax1000//不要分号//设计联系人结构体structPerson{ stringm_Name; intm_Sex; intm_Age; stringm_Phone; stringm_Addr; };//设计......
  • 【C++】string类(上)
    个人主页~string一、标准库中的string类1、什么是string类2、string类的常用接口讲解(1)string类的常见构造(2)string类的容量操作(3)string类对象的访问及遍历(4)string类对象的修改(5)string类非成员函数(6)其他(7)vs和g++下string结构说明vs下的string结构g++下string结构......