zoukankan      html  css  js  c++  java
  • 记录一下类成员方法作为模板函数踩到的坑

    记录一下类成员方法作为模板函数踩到的坑

    1、代码示例

    现有以下两种代码:

    代码1:

    //test.h
    class Test
    {
    public:
        template<class T>
        T func()
        {
            //doSomeThing
        }
    };
    

    代码2:

    //test.h
    class Test
    {
    public:
        template<class T>
        T func();
    }
    
    //test.cpp
    template<class T>
    T Test::func()
    {
        //doSomeThing
    }
    

    调用处代码相同:

    //main.cpp
    int main()
    {
        Test test;
        test.func();
        return 0;
    }
    

    2、现象说明

    以上两种代码看起来好像没什么问题,C++ 也通常是头文件声明,cpp实现,但是现象是:

    1. 代码1 没问题,代码2 链接报错了;
    2. 代码2 如果不调用,链接也不会报错;
    3. 报错信息和 函数只声明未定义 相同;

    3、原因

    这个问题是C++的模板定义造成的,C++编程思想 中说明了原因

    模板定义很特殊。由template<…>处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

    这就能解释了上面出现的两种现象。

    通俗地讲就是,C++ 代码在编译时,模板并不能生成真正的二进制代码,而是在调用模板的时候才会去找对应的声明以及实现,所以没有调用就不会报错

    但是编译器是分离式的,也就是说这时候,编译器是不知道模板定义的cpp文件的,所以在编译的时候,只有声明,没有定义,并且希望在链接的时候找到定义,所以编译的时候不会报错

    但是模板又不会生成二进制代码,所以链接肯定找不到,所以,报错在链接步骤,并且报错信息和函数只声明未定义相同

    这也是STL源码中所有头文件都包含模板定义的原因

    4、解决方法

    解决方法有两种

    法一: 使用 export 关键字

    //test.h
    class Test
    {
    public:
        export template<class T>
        T func();
    }
    

    缺点是:export 关键字不是不是所有编译器都支持的,比如 MSVC 和 gcc 都不支持

    法二: 定义和声明放在一起

    使用上述 代码1 的方式

  • 相关阅读:
    Oracle Instant Client(即时客户端) 安装与配置
    面试中经典的数据库问题
    MySQL 大表优化方案
    mysql中Timestamp,Time,Datetime 区别
    HTML学习之给div高度设置百分比不生效的问题
    textarea文本域宽度和高度width及height自动适应实现代码
    JAVA基础----java中E,T,?的区别?
    去除ArrayList集合中的重复自定义对象元素
    sql select中加入常量列
    mysql 将null转代为0
  • 原文地址:https://www.cnblogs.com/sherlock-lin/p/15644991.html
Copyright © 2011-2022 走看看