2012-04-29 44 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