0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

模版定义一定要写在头文件中吗?

汽车电子技术 来源:程序喵大人 作者:程序喵大人 2023-02-21 14:23 次阅读

大家在使用C++代码时或多或少都会使用到模板,使用模板时应该都是把定义放在了头文件中,因为放在源文件中定义会编译失败。

那问题来了,模板中的函数定义一定要写在头文件中吗?

先说结论:不一定要放在头文件中,定义也可以放在源文件中,但操作起来还是有点麻烦的。

继续往下看看

先看一段正常的模板代码:

// template.h
#include 


template <typename T>
struct TemplateTest {
    T value;
    void func();
};


template <typename T>
void TemplateTest::func() {
    std::cout << typeid(T).name() << std::endl;
}


// test_template.cc
#include "template.h"


int main() {
    TemplateTest<int> test;
    test.func();
    return 0;
}

这段代码没啥毛病,因为实现放在了头文件中,也会正常输出。

如果我把函数定义放在源文件中呢,会怎么样?

// template.h
#include 


template <typename T>
struct TemplateTest {
    T value;
    void func();
};


// template.cc
template <typename T>
void TemplateTest::func() {
    std::cout << typeid(T).name() << std::endl;
}


// test_template.cc
#include "template.h"


int main() {
    TemplateTest<int> test;
    test.func();
    return 0;
}

嗯,不出意外,编译报错了,报了个没有某个函数实现的error:

/tmp/ccPghOjU.o: In function `main':
test_template.cc:(.text+0x1f): undefined reference to `TemplateTest::func()'
collect2: error: ld returned 1 exit status

为什么没有此函数定义?

先补充个基础知识,模板的本质。本质其实就是类型泛化,可以用一个T代替多种类型,对于上面的模板,假如有此种使用:

TemplateTest<int> test;

那模板最终可能变成这样:

struct TemplateTest_int {
    int value;
    void func() {
        std::cout << typeid(int).name() << std::endl;
    }
};

如果有这两种使用:

TemplateTest test;
TemplateTest<float> test;

那模板最终可能会变成这样:

struct TemplateTest_int {
    int value;
    void func() {
        std::cout << typeid(int).name() << std::endl;
    }
};


struct TemplateTest_float {
    float value;
    void func() {
        std::cout << typeid(float).name() << std::endl;
    }
};

模板最终会展开成什么样,取决于用户是怎么使用它的。

那回到上面的问题,为什么把定义放在源文件中,编译就失败了呢,因为每个源文件的编译都是独立的,尽管在test_template.cc进行了TemplateTesttest的使用,但是在template.cc中却感知不到,所以也就没法定义相关的实现。

思路来了,只需要让template.cc中感知到T有int类型的情况,那编译应该就没问题。这里有个语法,叫模板实例化,像这样:

template struct TemplateTest<int>;

把这行代码放在template.cc中:

// template.cc
#include "template.h"


template <typename T>
void TemplateTest::func() {
    std::cout << typeid(T).name() << std::endl;
}


template struct TemplateTest<int>;

整个代码的编译就没得问题了,通过这种方式即可以实现模板函数声明与实现的分离。

这也印证了上面的结论。

这里我再抛出 几个问题 ,大家可以讨论讨论:

  • 模板的使用是否会导致代码段体积增大?怎么解决?
  • 模板的函数定义放在了头文件中,好多个源文件都include此头文件,是否会导致函数的multi definition类型的链接报错?实际使用中貌似没有报错,为什么?大家有想过吗?
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72900
  • 头文件
    +关注

    关注

    0

    文章

    22

    浏览量

    9795
  • 源文件
    +关注

    关注

    0

    文章

    30

    浏览量

    4519
收藏 人收藏

    评论

    相关推荐

    头文件寄存器的定义方式

    本帖最后由 mr.pengyongche 于 2013-4-30 03:14 编辑 图片中是TMS320LF2407开发板自带的实例程序,头文件定义寄存器的方式与2812
    发表于 05-30 16:18

    modelsim中一定要写testbench文件吗?

    modelsim中一定要写testbench文件吗?
    发表于 03-29 10:02

    定义下的“GPIO_”是什么作用,一定要用吗

    #defineGPIO_KEY P1//独立键盘用P1口#defineGPIO_LED P0//led使用P0口我想知道这个宏定义下的“GPIO_”是什么作用,一定要用吗?c程序的GPIO_与通讯输入\输出的GPIO是同
    发表于 05-29 12:22

    头文件定义全局变量的方法

      教大家个如何在头文件定义全局变量的方法  通常情况下,都是在C文件
    发表于 07-04 08:34

    请问如何理解头文件的#ifndef?

    要写句#defined LED.H 因为#ifndef 后面的字符串 不管是 LED.H还是__LED_H和头文件的名字没有半毛钱关系。只不过是为了读程序的时候方便而已。其实那个字符串只要合法的就行了
    发表于 07-06 03:34

    头文件定义全局变量的方法介绍

      教大家个如何在头文件定义全局变量的方法  通常情况下,都是在C文件
    发表于 07-09 09:25

    头文件定义驱动版本号的方法

    configuration file!#endif看到这个判断让我想起了之前搞FATFS移植时也有这样使用过,然后我找到FATFS源代码看果然有,FATFS源代码中头文件定义:#ifndef
    发表于 07-30 20:16

    变量在源文件头文件定义问题

    (void);g#endif FlagStatus是已定义的枚举变量,想问下,__IO FlagStatusTime_1ms_flag已经在stm32f10x_it.c源文件做了
    发表于 03-12 03:04

    STC12C5A08S2专用头文件

    STC12C5A08S2专用头文件,兼容51免去定义端口的麻烦
    发表于 10-28 17:08 54次下载

    如何在C++代码中使用C头文件

    如何在C++代码中使用C头文件。从C++调用C头文件之前,C头文件必须包含在extern C命令中。本节包含以下两部分内容: 在C++中使用系统的C头文件; 在C++中使用自
    发表于 10-19 09:24 3次下载

    教大家一个如何在头文件定义全局变量的方法

    通常情况下,都是在C文件定义全局变量,在头文件中声明,但是,如果我们定义的全局变量需要被很多的C文件使用的话,那么将全局变量
    发表于 12-04 14:55 19次下载

    单片机-头文件

    reg52.h头文件的作用在代码中引用头文件,其实际意义是将头文件中的所用内容都放到引用头文件的地方下面是reg52.h头文件的内容:/*-
    发表于 11-23 17:21 17次下载
    单片机-<b class='flag-5'>头文件</b>

    MCU_头文件编写

    头文件中一般放一些重复使用的代码,如:常量、变量、宏等的定义,函数的声明。当使用#include语句引用头头文件时,相当于将头文件中的内容复制到#include处。
    发表于 12-05 10:36 5次下载
    MCU_<b class='flag-5'>头文件</b>编写

    【笔记】单片机头文件的顺序会让程序报错?

    单片机程序中的头文件对程序的影响非常重要。头文件包含了函数、宏、结构体和其他声明的定义,它们提供了程序所需的各种功能和库。头文件的正确顺序可以确保程序能够正确编译、链接,并正确地使用所
    的头像 发表于 05-19 09:50 914次阅读
    【笔记】单片机<b class='flag-5'>头文件</b>的顺序会让程序报错?

    什么是头文件头文件编写的一般格式要求是怎样?

    本文介绍头文件定义、编写、保存及引用等方面的内容,包括了一般的格式要求、例程等。
    的头像 发表于 11-08 16:25 914次阅读
    什么是<b class='flag-5'>头文件</b>?<b class='flag-5'>头文件</b>编写的一般格式要求是怎样?