• [转]C++ 函数模板特化导致的多重定义链接错误


    标题说的可能不是很清楚,解释一下,函数模板,一般都是放在头文件里面,所以有些时候,我也会做一个特化,也放在这个头文件里面,当这个头文件出现多次的包含之后,就会出现链接多重定义的错误,先说一个例子,如下:

    现象描述

    有文件"header.h"

    #ifndef HEADER  
    #define HEADER  
      
    template <class T>  
    size_t size_rb_tree_node()  
    {  
        return 20; /*constant value for l r p pointer and (color & height) and void * value*/  
    }  
      
    template <>  
    size_t size_rb_tree_node<void *>()  
    {  
        return 30;  
    }  
      
    #endif  
    

      

    "Source.cpp"

    #include "Header.h"  
      
    int count()  
    {  
        int a = size_rb_tree_node<int>();  
      
        return a;  
    }  

     "main.cpp"

    #include "Header.h"  
      
    using namespace std;  
      
    int count();  
      
    int main()  
    {  
        int a = size_rb_tree_node<int>();  
        a = size_rb_tree_node<void *>();  
    }  
    

      

    编译后,在链接的时候报错了:

    1>------ Build started: Project: Win32Project1, Configuration: Debug Win32 ------  
    1>  AllocatorNew.cpp  
    1>Source.obj : error LNK2005: "unsigned int __cdecl size_rb_tree_node<void *>(void)" (??$size_rb_tree_node@PAX@@YAIXZ) already defined in AllocatorNew.obj  
    1>C:Users	ianzuozDocumentsVisual Studio 2012ProjectsWin32Project1DebugWin32Project1.exe : fatal error LNK1169: one or more multiply defined symbols found  
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========  
    

      

    其实原因很简单了,因为特化后的函数就是一个普通函数,这个和在一个头文件里面定义一个函数,然后多出include这个头文件一样的结果,都会导致多重定义。

    解决方法

    1、把特化的函数,添加inline标记,这样,编译器不会给这个函数生成一个函数符号,就当作是一个宏展开吧,不过,有些编译器不一定会inline的。行不行试试就知道了,如下:

    #ifndef HEADER  
    #define HEADER  
      
    template <class T>  
    size_t size_rb_tree_node()  
    {  
        return 20; /*constant value for l r p pointer and (color & height) and void * value*/  
    }  
      
    template <>  
    inline size_t size_rb_tree_node<void *>()  
    {  
        return 30;  
    }  
      
    #endif  
    

      

    2、让这个函数成为文件域,也就是不参与全局link,也是可以的:

    #ifndef HEADER  
    #define HEADER  
      
    template <class T>  
    size_t size_rb_tree_node()  
    {  
        return 20; /*constant value for l r p pointer and (color & height) and void * value*/  
    }  
      
    template <>  
    static size_t size_rb_tree_node<void *>()  
    {  
        return 30;  
    }  
      
    #endif  
    

      

    3、还有一个办法就是,把这个特化从头文件里面拿出去,放在需要的实现文件里面,再添加static属性。

  • 相关阅读:
    线段树总结
    c语言实现按层次(广度优先)非递归遍历二叉链树
    三、初学.NET—Gridview的分页
    五、初学.NET—Gridview自动编号和鼠标停留行加背景
    四、初学.NET—Gridview外部按钮选中、删除一行
    二、初学.NET—Gridview的排序
    一、初学.NET—数据库连接字符串
    .net web study
    C# 接口
    c#索引器
  • 原文地址:https://www.cnblogs.com/arsblog/p/4838043.html
Copyright © 2020-2023  润新知