问题
First question on stackoverflow :) I'm relatively new to C++, and have never used templates, so forgive me if I'm doing something silly. I have a template function that combs through a list and checks for a specified element of a general type. That way I can specify whether it's looking for a string, or an int, or whatever.
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;
};
This is my call to inList()
. testvec
is a string vector with a few elements, including "test":
if (inList<string>("test", testvec))
cout << "success!";
else cout << "fail :(";
To my dismay and confusion, upon compiling, I am slapped with the following error:
error: no matching function for call to 'inList(const char [5], std::vector<std::basic_string<char> >&)'
What am I doing incorrectly? :(
[EDIT] I neglected to mention that the template definition is in the global namespace. (it's a simple test program to see if my template will work, and it does not, apparently :( )
回答1:
That's because there is no way to convert from a std::vector to a std::string. Instead, what you need to do is abstract over the concept of a collection.
You do this so that people can pass in any collection type they want. They can use an array, a vector, a string, a list, a deque... as long as it fits the 'concept' of a collection (here's to hoping c++1x comes with concepts!). They can even use their own in-house specially optimized collection types. That's the beauty of templates.
Using C++11 (works with any standard collection, primitive arrays, and user-defined types):
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;
}
EDIT: It's a non-standard extension to deduce std::initializer_list as a template argument, so provide an explicit override:
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;
}
With this version, you can call it like:
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;
}
And for those of us still in C++98, this will work for both strings and vectors, and some user-defined types. It will not work with raw arrays though.
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;
}
Or, you can go STL style:
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());
If I made a mistake, sorry, I don't have my compiler running right now...
来源:https://stackoverflow.com/questions/10369464/template-function-gives-no-matching-function-for-call-error