一个C++模板有意思的小实验

看面经遇到一个C++模板的问题,顺手做了下实验看看结果,觉得比较有意思就记录一下


我们一般用模板会把声明和定义放在一起(放在同一个头文件内),那么如果我们在一个头文件内声明我们要使用的模板函数,并在另一个cpp文件内实现会怎么样?

// funcT.h
#pragma once
#include <iostream>

template<typename T>
void func2(T const& a, T const& b);
// funcT.cpp
#include "funcT.h"
#include <iostream>

template<typename T>
void func2(T const & a, T const & b)
{
    
    
    T c = a + b;
    std::cout << "func4" << std::endl;
    return ;
}

g++ -c funcT.cpp -o funcT 编译一下,没问题。

在另一个文件内使用函数

// main.cpp
#include <iostream>
#include "funcT.h"

int main()
{
    
    
    int x = 3;
    int y = 2;
    func2(x, y);

    return  0;
}

g++ -c main.cpp -o main 编译一下也没问题。

然后我们将两个目标文件链接为一个可执行文件,很遗憾报错了,具体错误是对 void func2<int>(int const&, int const&) 未定义的引用

这是为什么呢,我们明明已经给了一个具体的定义,为什么链接器找不到呢。

我们在 func.cpp 中加一段代码

// funcT.cpp
#include "funcT.h"
#include <iostream>

template<typename T>
void func2(T const & a, T const & b)
{
    
    
    T c = a + b;
    std::cout << "func4" << std::endl;
    return ;
}

void caller()  {
    
    
    func2(3, 4);
}

再编译->汇编->链接,不报错了,且能正常输出结果。

本质原因是模板是需要在编译的时候展开的,本身就不能算是“声明/定义”,或者说只是模板的声明和定义,而没有具体函数的定义,我们编译 func2.cpp,对于第一个版本,里面没有调用 func2(T const& a, T const& b) 的代码,所以编译器没有展开模板的任何实现。所以,我们在 main.cpp 中调用的时候,展开的只是一个声明,定义是缺失的,所以链接的时候会报错。

而第二个版本,我们在 func2.cpp 中加入了一个 caller 函数,里面实际调用了func2函数,所以在编译的时期生成了具体的函数定义,那么在链接的时候就能找到。

通过这个实验,更明确了模板展开是编译期行为。

另一个有意思的实验

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/141173189