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

    文章

    2094

    浏览量

    73442
  • 头文件
    +关注

    关注

    0

    文章

    24

    浏览量

    9835
  • 源文件
    +关注

    关注

    0

    文章

    30

    浏览量

    4564
收藏 人收藏

    评论

    相关推荐

    Linux下个实用的头文件

    queue.h是Linux、FreeBSD头文件
    发表于 12-02 11:48 843次阅读

    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

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

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

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

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

    编程引用头文件的几种方法及要点

    好的编程习惯,会直接影响代码的质量,在嵌入式C/C++头文件的引用方式和方法有多种,同时些细节也会影响你代码质量和编译效率。 下面就来说说与头文件有关的知识; 1 引号“”和尖括
    的头像 发表于 03-12 17:30 3270次阅读

    在keil创立头文件

    定义格式#ifndef _LED_H_#define _LED_H_ //跟在后面的_LED_H_只是文件名//内容#endif用51单片机举例注意在头文件
    发表于 11-21 14:06 2次下载
    在keil<b class='flag-5'>中</b>创立<b class='flag-5'>一</b>个<b class='flag-5'>头文件</b>

    keil添加了头文件仍然报找不到头文件的原因

    ,则需要重新将文件夹包含到工程。4)点击魔术棒的C/C++,将包含该头文件的最内层文件夹包含进去,
    发表于 11-21 14:21 13次下载
    keil添加了<b class='flag-5'>头文件</b>仍然报找不到<b class='flag-5'>头文件</b>的原因

    单片机-头文件

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

    MCU_头文件编写

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

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

    头文件的正确顺序主要涉及以下几个方面:1.依赖关系和声明顺序:在编写单片机程序时,可能会有头文件之间存在依赖关系。某些头文件
    的头像 发表于 05-19 09:50 1455次阅读
    【笔记】单片机<b class='flag-5'>头文件</b>的顺序会让程序报错?

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

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

    请问头文件能不能定义变量呢?

    最近在编译个工程的时候,突然遇到了变量重复定义的问题,根据提示打开这几个 C 文件,并没有发现定义变量的地方。后来再找找,原来变量
    的头像 发表于 04-28 09:33 977次阅读

    可重复头文件的固定结构

    年轻人,你可曾记得,在修习C语言的时候,见过这样的字句:在创建头文件的时候,一定要加入保护宏。
    的头像 发表于 08-29 10:23 272次阅读
    可重复<b class='flag-5'>头文件</b>的固定结构