2015-10-21 164 views
1

我有一個頭文件中聲明的函數模板。該功能是一個歸檔器,應該支持通過該項目實施的其他幾種類型(類)。這個想法是有一個基本的模板聲明,每個類然後專門針對它自己的類型。完全專業化的模板功能

// Archiver.h 
template <class T> void archive(Archiver & archiver, const T & obj); 

該方法沒有實現。現在我創建一個類(例如,Header),我希望它可以存檔。因此,我的意圖是專門化該方法。這是我現在有:

// Header.h 
extern template void archive(Archiver & archiver, const Header & obj); 

我宣佈的功能extern因爲我在.cpp文件

// Header.cpp 
template <> void archive(Archiver & archiver, const Header & obj) 
{ 
// Code here 
} 

這給specialization after instantiation實現它。我試過其他的組合,以及:

  1. 在頭文件中直接實現,因爲通常建議模板:我得到「多重定義」在.cpp文件
  2. 實施不會對頭部的聲明:當從另一個編譯單元調用該方法時,我得到undefined reference

那麼實現這個的正確性是什麼?

編輯:

起初,我決定去,因爲逆過程的模板,解除存檔。基本上我可以寫unarchive<Header>()而不是unarchive_header()這似乎更合適。

我相信我也應該提一下,我正在編譯使用Android Studio和Gradle構建系統,這就是爲什麼我使用gcc而不是g ++。我也給海灣合作委員會下列編譯器選項:

-std=gnu++11 -fexceptions -fpermissive -lstdc++ 

-fpermissive是一種絕望的行爲。

+1

爲什麼不使用單獨的函數? – melpomene

+0

除非你有一個非常好的理由將歸檔作爲一個單獨的函數,否則我建議用其他方法來完成:使用你想要實現的類的虛擬方法(以及可以實現的所有類的ABC /接口) 。這就是我會用的。 –

回答

5

只要不使用模板:

// Header.h 
void archive(Archiver & archiver, const Header & obj); 

// Header.cpp 
void archive(Archiver & archiver, const Header & obj) 
{ 
// Code here 
} 

簡單多了這種方式。只需對archive()進行非限定的調用,並確保此過載在與Header相同的名稱空間中聲明,並讓ADL發揮它的魔力。

+0

我相信在那個時候我決定使用模板,因爲反向處理,取消存檔。我可以寫'unarchive

()',而不是'unarchive_header()'。我認爲第一種形式更方便 –

+0

@AndréFratelli爲什麼你認爲你必須寫'unarchive_header()'?只需寫'unarchive()'。 – Barry

+0

因爲'Header'不是唯一不可讀的類,並且這個函數不會被覆蓋,因爲它沒有得到任何參數 –

2

爲什麼要使用函數模板?

你說:

的想法是有一個基本模板的聲明,每個類,然後專門到它自己的類型。

如果一個函數模板沒有默認實現,那麼根本沒有意義。你可以使用:

extern void archive(Archiver & archiver, const Header & obj); 

當你需要它時。

如果你必須使用一個函數模板

extern template void archive(Archiver & archiver, const Header & obj); 

是不對的。它需要是:

template <> void archive<Header>(Archiver & archiver, const Header & obj); 

該實現需要使用相同的簽名。

template <> void archive<Header>(Archiver & archiver, const Header & obj) 
{ 
} 

更新,響應OP的評論

我嘗試以下,以模擬你的情況。

socc.h:

#pragma once 

struct Archiver {}; 

template <class T> void archive(Archiver & archiver, const T & obj); 

struct Header {}; 

template <> void archive<Header>(Archiver & archiver, const Header & obj); 

socc.cc:

#include <iostream> 
#include <string> 

#include "socc.h" 

int main() 
{ 
    Archiver ar; 
    Header obj; 
    archive(ar, obj); 
} 

socc-2.cc:

#include "socc.h" 

template <> void archive<Header>(Archiver & archiver, const Header & obj) 
{ 
} 

命令編譯:

g++ -std=c++11 -Wall socc.cc socc-2.cc -o socc 

該程序已成功構建。

+0

第二種方法在調用點提供「未定義的引用」。我仍在研究不使用模板。 –

+0

@AndréFratelli,請參閱更新。 –

+0

你可以讓它與gcc一起工作嗎?我試着添加'-lstdC++'編譯器標誌。我最初沒有提及它(它看起來不相關),但我使用Gradle爲Android構建。我也在研究如何用gradle –

0

在這種情況下,我認爲,重載只是伎倆。這裏你不需要模板。

void archive(Archiver & archiver, const Header & obj); 
void archive(Archiver & archiver, const Footer & obj); 
void archive(Archiver & archiver, const Whatever & obj);