2017-07-20 48 views
1

我對C++模板語法有些不穩定,所以我不確定我想象的是否可能,如果是,對正確的語法不清楚。模板函數檢查「is int」/「is double」/ etc

我想實現像template<int> bool is(std::string&)template<double> bool is(std::string&)等模板函數,這樣我可以打電話is <int> (...)is <double> (...)代替isInt(...)isDouble(...),等這可能嗎?如果是這樣,你將如何編寫函數簽名?

隨着我的模板語法的微妙把握,我的嘗試是:

#include <iostream> 
#include <cstdlib> 

template<int> 
bool is(std::string& raw) 
{ 
    if (raw.empty()) return false; 
    char* p; 
    int num = strtol(raw.c_str(), &p, 10); 
    return ((*p != '\0') ? false : true); 
} 

int main(int argc, char* argv[]) 
{ 
    std::string str("42"); 
    std::cout << std::boolalpha << is <int> (str) << std::endl; 
    return 0; 
} 

這失敗,出現以下錯誤:

>g++ -g main.cpp 
main.cpp: In function ‘int main(int, char**)’: 
main.cpp:16:51: error: no matching function for call to ‘is(std::string&)’ 
    std::cout << std::boolalpha << is <int> (str) << std::endl; 
               ^
main.cpp:5:6: note: candidate: template<int <anonymous> > bool is(std::string&) 
bool is(std::string& raw) 
    ^
main.cpp:5:6: note: template argument deduction/substitution failed: 
+0

非類型模板參數需要*值*不是類型。我建議你閱讀[* template specialization *](http://en.cppreference.com/w/cpp/language/template_specialization)。 –

+1

你可能會很快得到答案,但我的建議只是「不要」。它使用與模板相關的語法對代碼進行混淆,只有這樣您才能在調用站點上獲得一點點語法糖。 – StoryTeller

+0

@StoneThrowThrow對不起,第一條評論只是一個誤解,刪除它;) – user463035818

回答

6

我到您的文章承受評論,很容易做到這一點的方法是與使用std::istringstream類來分析一個簡單的模板:

template<typename T> 
bool is(std::string const& raw) { 
    std::istringstream parser(raw); 

    T t; parser >> t; 
    return !parser.fail() && parser.eof(); 
} 

明顯的警告是T必須是默認施工的。但從好的一面來說,上述內容也適用於用戶定義的類型,只要它們實現了operator >>即可。

+0

這很聰明,並且由於缺乏使用而暴露了其他我不熟悉的東西:'>>'操作符。所以如果我正確地解釋這個,'istringstream :: >>'操作符會「嘗試」將字符串解析到它的右手操作數中 - 是嗎? – StoneThrow

+1

@StoneThrow - 'operator >>'實際上是一個特殊的函數名稱。 C++代碼可以爲用戶定義的類型實現它,當使用這些類型寫入「A >> B」時,它將被選擇爲過載恢復。標準流類(由用戶定義)已經超載它們以允許「輸入」所有基本類型。但是如果你寫了你的類,你可以自己添加一個'operator >>(istream&,myClass&)'函數。是的,如果所需的解析失敗,解析器狀態將返回'fail()== true'。 – StoryTeller

+0

該解決方案的問題:'是(「1976 Dodge Van」)是'true'。你可能想把它改成'!parser.fail()&& parser.eof()' - 我不太確定,但是沒有另一個流聲明潛在的「細節」。 – peterchen

3

您需要使用模板特此:

#include <iostream> 
#include <cstdlib> 

template<class T> bool is(std::string& raw) = delete; 

template<> 
bool is<int>(std::string& raw) 
{ 
    if (raw.empty()) return false; 
    char* p; 
    int num = strtol(raw.c_str(), &p, 10); 
    return ((*p != '\0') ? false : true); 
} 

int main(int argc, char* argv[]) 
{ 
    std::string str("42"); 
    std::cout << std::boolalpha << is <int> (str) << std::endl; 
    return 0; 
} 

您可以在here

中查看更多信息
+1

如果我可以提出一個建議。您可以將'= delete'添加到主模板。這會在編譯時早期(而不是鏈接時間)提供類型不受支持的體面錯誤。 – StoryTeller

+0

我從中學到的一件事就是需要「函數原型」或「非專業模板原型」。 (代碼第4行的正確術語是什麼?)。與等效的非模板函數相反,如果在使用之前解析原型,則不需要原型。 – StoneThrow

+1

@StoryTeller我不知道這是可能的 - 很高興知道。謝謝你的提示。 –