2012-04-29 60 views
0

關於stackoverflow的第一個問題:)我相對較新的C++,並從未使用模板,所以原諒我,如果我做一些愚蠢的事情。我有一個模板函數,通過列表梳理並檢查一般類型的指定元素。這樣我可以指定它是查找一個字符串,還是一個int,或其他。模板函數給出「沒有匹配函數的調用」錯誤

template <class T> 
bool inList(T match, std::string list) 
{ 
    int listlen = sizeof(list); 
    for (int i = 0; i <= listlen; i++) { 
     if (list[i] == match) return true; 
     else continue; 
    } 
    return false; 
}; 

這是我撥打inList()testvec是與幾個元素的字符向量,包括「測試」:

if (inList<string>("test", testvec)) 
    cout << "success!"; 
else cout << "fail :("; 

令我感到沮喪和困惑,在編譯時,我有以下錯誤耳光:

error: no matching function for call to 'inList(const char [5], std::vector<std::basic_string<char> >&)' 

我在做什麼不正確? :(

[編輯] 我忘了提及的是,模板定義在全局命名空間。(這是一個簡單的測試程序,看看我的模板將工作,這不,顯然是:()

回答

4

這是因爲沒有辦法將std :: vector轉換爲std :: string,而是需要抽象概念集合。

這樣做是爲了讓人們可以通過他們可以使用數組,矢量,字符串,列表,deque ...只要它符合集合的'概念'(這裏希望C++ 1x帶有概念!)他們甚至可以使用自己的內部特別優化的收集類型。這就是模板的美妙之處。

使用C++ 11(適用於任何標準的集合,原始陣列,和用戶定義的類型):

template<class elem_t, class list_t> 
bool in_list(const elem_t& elem, const list_t& list) { 
    for (const auto& i : list) { 
     if (elem == i) { 
     return true; 
     } 
    } 
    return false; 
} 

編輯:這是一個非標準擴展來推斷的std :: initializer_list作爲模板參數,所以提供一個明確的控制裝置:

template<class elem_t> 
bool in_list(const elem_t& elem, std::initializer_list<elem_t> list) { 
    for (const auto& i : list) { 
     if (elem == i) { 
     return true; 
     } 
    } 
    return false; 
} 

在這個版本中,你可以這樣調用它:

int main() { 
    std::vector<int> a = {1, 2, 3, 4, 5}; 
    std::cout << in_list(3, a) << std::endl; 
    std::string b = "asdfg"; 
    std::cout << in_list('d', b) << std::endl; 
    std::cout << in_list('d', "asdfg") << std::endl; 
    std::cout << in_list(3, {1, 2, 3, 4, 5}) << std::endl; 
    return 0; 
} 

對於我們這些仍然使用C++ 98的人來說,這將適用於字符串和向量以及一些用戶定義的類型。儘管如此,它仍然不能用於原始數組。

template<class elem_t, class list_t> 
bool in_list_98(const elem_t& elem, const list_t& list) { 
    list_t::const_iterator end = list.end(); //prevent recomputation of end each iteration 
    for (list_t::const_iterator i = list.begin(); i < end; ++i) { 
     if (elem == *i) { 
     return true; 
     } 
    } 
    return false; 
} 

或者,你可以去STL風格:

template<class elem_t, class iterator_t> 
bool in_list_stl(const elem_t& elem, iterator_t begin, iterator_t end) { 
    for (iterator_t i = begin; i < end; ++i) { 
     if (elem == *i) { 
     return true; 
     } 
    } 
    return false; 
} 
//call like std::string s = "asdf"; in_list_stl('s', s.begin(), s.end()); 

如果我犯了一個錯誤,對不起,我沒有我的編譯器現在正在運行...

+0

該品種是好的。簡短的答案是傳遞一個字符串,而不是一個字符串向量,期望它轉換爲一個字符串。儘管如此,在技術上有'include()'或'find()';沒有必要自己寫一個堅實的) – chris 2012-04-29 03:45:59

+0

我認爲克里斯在我刷新我的頁面之前刪除了他對我的問題的評論,因爲它已經不存在了,因爲他提到的解決了我的問題。我感覺很傻。我有'std :: string'作爲'inList()'的參數,因爲我不知道我可以直接使用'std :: vector '。我想我應該使用'std :: string',因爲這是向量所帶來的,但是現在我感到無聊的回顧它。**謝謝你的迴應,你的迴應也有助於未來的參考,羅伯特:)** – ZeroKnight 2012-04-29 03:54:35

+0

如果你使用std :: includes或std :: find,只記得對end()進行測試。 in_list(a,b)== [](const auto&a,const auto&b){return std :: find(b.begin(),b.end(),a)!= b.end(); } - 我的意思是說lambda是一種抽象,而不是實際的代碼 - 我知道我們沒有多態lambda表達式。這是我們現在必須與haskell一起離開的事情。 – 2012-04-29 04:08:57