2013-03-01 84 views
1

我有一個功能強制功能模板/函數重載爲特定類型

foo(int, int, int, int/long long/_int64/double/long double/char *, int ONLY IF previous char * - otherwise unneeded)

問題是,字符*實現要比值類型,由於進行字符串拷貝不同。是的,這是一箇舊代碼的接口,所以我不能使用std :: string:/

目前,我已經把它作爲模板,並且有一個函數重載char *,並帶有額外的參數。但是,其他類型的所有操作在char *上也是有效的,所以如果調用者忘記了最後一個參數,則該函數默默地匹配模板,而不是產生錯誤的邏輯。

有沒有什麼辦法可以強制使用函數模板中的重載/使用默認參數/這將允許特定類型的不同簽名(額外參數),而不會默認匹配較小的簽名?

更多: 尚未獲得C++ 11的許可,但我很樂意看到使用它來幫助推動採用的建議。 沒有提升,但與上面相同

我也曾嘗試

return_type foo(int,int,int,typename std::enable_if<!std::is_pointer<T>::value, T>::type & value2update)

沒有任何的運氣。然後它聲稱帶雙&參數的呼叫無法匹配。

+0

你是什麼意思,「否則不需要」?這應該通過重載輕鬆實現。 – Xeo 2013-03-01 23:42:01

+0

我假設額外的'int'是一個長度?你可以採取[StringPiece](http://code.google.com/p/re2/source/browse/re2/stringpiece.h)來避免完全需要特殊外殼? – 2013-03-01 23:43:07

+0

@Xeo,是的,我只是想避免每種類型的代碼重複,所以想要templatize其他類型,這些都共享完全相同的代碼。 @ Scott Lamb,是的,肯定這是一個有效的 - 也許是最好的選擇。然而,這種集成將發生在代碼庫的大約3000個地方,所以不得不在調用代碼中添加StringPiece創建邏輯,這是我想避免的。我只是希望有一些事情我做錯了強制專業化 - 必須更徹底地調查Thomas的答案 – 2013-03-04 15:39:56

回答

2

你可以讓你的鏈接幫助。聲明,但沒有定義,你的函數模板,char*超載頭:

template<typename T> 
foo(int, int, int, T); 
foo(int, int, int, char*, int); 

在實現文件(的.cpp/.cc的),同時實現:

template<typename T> 
foo(int, int, int, T) { ... } 

foo(int, int, int, char*, int) { ... } 

,並明確實例版本對於類型要接受:

template<> 
foo(int, int, int, int); 
template<> 
foo(int, int, int, long long); 
// etc. 

如果我理解正確,ScottLam b在評論中暗示了這樣的事情。頭文件:

foo(int, int, int, int); 
foo(int, int, int, long long); 
... 
foo(int, int, int, char*, int); 

執行文件(.cpp /。立方厘米):

namespace { 
    template<typename T> 
    foo_tmpl(int, int, int, T) { ... } 
} 

foo(int, int, int, int) { foo_tmpl(...); } 
foo(int, int, int, long long) { foo_tmpl(...); } 
.... 
foo(int, int, int, char*, int) { ... } 

這是從使用報頭的人的觀點考慮,優選(它們可以立即看到哪些重載是可用的),但需要對實施側略微更多的工作。

+1

恕我直言,如果列出每個支持的過載,恕我直言,標題將更直接/可讀。如果定義不平凡,您可以委託給實現文件中的匿名名稱空間中的模板函數以減少重複。 – 2013-03-02 02:12:50

+0

從外觀來看,這是最好的答案。要明確,是頭文件還是cpp文件中的顯式實例? @ScottLamb你會不會解釋你的評論?你是說如我剛剛提到的那樣,實例化應該在頭文件中列出,然後在cpp文件中定義它?順便說一句,如果這改變了事情,這個整個類在一個命名空間範圍 – 2013-03-04 15:56:54

+1

更新我認爲他的意思。 – Thomas 2013-03-04 17:18:07

1

使用一個輔助類string_ref捆綁的兩個參數爲您提供:

class string_ref { 
    const char *str; 
    std::size_t len; 
public: 
    string_ref(std::string const& s) 
    : str(s.c_str()), len(s.size()) {} 

    string_ref(const char *c, std::size_t len) 
    : str(c), len(len) {} 

    const char * c_str() const { return str; } 
    std::size_t size() const { return len; } 
}; 

然後

foo(int, int, int, int/long long/_int64/double/long double/const char*, [int]) 

只需添加

foo(int, int, int, string_ref) 
{ 
    foo(int, int, int, c_str(), size()); 
} 

一個string_ref可以創建從const char*int沒有開銷,兩者都可以輕鬆提取以便進一步傳遞給C函數。

(命名string_refnot random。)

+1

這不安全!只要字符串對象仍然存在並且未被修改,'std :: string :: c_str()'只是有效的。 – Thomas 2013-03-01 23:47:20

+1

如果小心使用,我不會看到問題。 'foo(...,string_ref(std :: string(「ok」)))'例如應該沒問題。 – ipc 2013-03-01 23:49:24

+0

我喜歡這個答案,因爲它是它應該完成的方式,我想 - 非常接近使用std :: string。另外,我讚賞沒有任何開銷的評論 - 在這種情況下這是非常關鍵的問題,而在其他情況下,在分析之後,更加優雅的面向對象的解決方案已經以原始速度被丟棄。它真的是「不」嗎?我無法看到如何爲此string_ref對象生成實際分配彙編程序指令。 – 2013-03-04 16:51:18