2012-08-01 19 views
4
// problem.cpp: 
#include <string> 

template<typename T> void func(const T & v); 

int main() { 
     int i; 
     float f; 
     char * cp; 
     char ca[4]; 

     func(i); 
     func(f); 
     func(cp); 
     func(std::string("std::string")); 
     func(ca); 
     func("string_literal"); 

     return 0; 
} 

// problem2.cpp 
#include <string> 

template<typename T> void func(const T & v); 

// undefined reference to `void func<int>(int const&)' 
template<> void func<int>(const int & v) { } 

// undefined reference to `void func<float>(float const&)' 
template<> void func<float>(const float & v) { } 

// undefined reference to `void func<char*>(char* const&)' 
template<> void func<char *>(char * const & v) { } 

// void func<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) 
template<> void func<std::string>(std::string const & v) { } 

// undefined reference to `void func<char [4]>(char const (&) [4])' 
// ??? 

// undefined reference to `void func<char [15]>(char const (&) [15])' 
// ??? 

找到的兩種解決方案:如何專門模板函數讓它接受傳遞一個char數組作爲參數?

一)在problem2.cpp:

template<> void func<char[4]>(const char (&v)[4]) { } 
template<> void func<char[15]>(const char (&v)[15]) { } 

二)problem.cpp:

template<typename T, unsigned N> void func(const T (&v)[N]) { func(v+0); } 
and then in problem2.cpp, add the newly missing 
template<> void func<const char *>(const char * const & v) { } 

對不起akappa,不得不再次修改,以澄清他們是兩個獨立的解決方案...

akappa:我唯一的方法通過編輯它可以爲此問題添加一些內容。我也不能評論也不能添加答案。可能與某些事情有關»Stack Overflow需要來自另一個域的外部JavaScript,該域被阻塞或無法加載。「我不知道如何解決,因爲我不知道SO究竟是如何告訴我的。

+10

不要專門函數模板。真的,*不要*。 – Xeo 2012-08-01 11:19:46

+0

@akappa:足夠了 - http://www.gotw.ca/publications/mill17.htm – Xeo 2012-08-01 11:41:56

+0

@Xeo:我沒有刪除我的評論,因爲那是我在google上通過簡單搜索獲得的第一個鏈接;) – akappa 2012-08-01 11:46:41

回答

3

功能特化是棘手的,因爲它們必須與參數的類型完全匹配。在數組的情況下(字符串文字也是一個數組),編譯器將執行類型推導並找出確切的類型,然後它會在程序中尋找特定的符號。

特別是,ca類型爲char[4],因此調用模板時,推導出的類型是T == char[4]和函數簽名,它希望找到的是void func<>(const char (&)[4]) 作爲你的兩個解決方案,它們是完全不同的方法。在第一種情況下,您正在專門使用特定類型的模板。這將變得很痛苦,就像你使用的每個新的字符串字面大小或類型一樣,你需要手動添加一個專門化。這是偶然爲什麼模版應該(往往不是)在標題中定義的原因,這樣你就不需要在明確實例(*)所有可能的模板參數...

第二種解決方案完全不同。在這種情況下,您將創建第二個不相關的(某種程度上)基本模板。該基礎模板獲取一個指向數組第一個元素的指針,並用該指針調用原始模板,從而有效地更改類型(並在流程中丟失信息:現在大小已丟失)。此時,所有使用數組的調用都將與第二個模板匹配,並作爲調用指針轉發給原始模板,從而減少專用於數組大小的需求(編譯器解決這些特化問題)。

還要注意的是,如果你只想讓路過字符數組,調度模板不必接受所有類型,它可能有一個非類型參數:

template <std::size_t N> 
void f(const char (&a)[N]) { f(&a[0]); } 

總結:

避免功能的模板特化,因爲這些處理起來很麻煩。數組的類型包含大小,這反過來意味着您需要針對每個可能的數組大小對進行專門的。或者,您可以添加一個輔助模板,該模板將分派給您的原始模板,並將其轉換爲指針。


*請注意,如果每個和所有專業的實現是一樣的,你能避免專業(和複製的代碼),而由在.cpp提供模板的定義,然後保持相同的行爲手動實例模板:

template <typename T> void func(T const &) { 
    // code goes here 
} 
template void func<int>(int const &); 
template void func<double>(double const &); 
//... 
相關問題