C++関数テンプレートの特化による多重定義リンクエラー

2457 ワード

タイトルの言うことははっきりしていないかもしれませんが、説明すると、関数テンプレートは、一般的にヘッダファイルの中に置かれているので、私も特化して、このヘッダファイルの中にも置かれています.このヘッダファイルに何度も含まれていると、リンクの多重定義のエラーが発生します.まず、一例を言います.以下のようにします.
現象の説明
「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\tianzuoz\Documents\Visual Studio 2012\Projects\Win32Project1\Debug\Win32Project1.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

実は原因はとても簡単で、特化した関数は1つの普通の関数なので、これは1つのヘッダファイルの中で1つの関数を定義して、それから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属性を追加することです.