Compiler error with using std::list - c++

I have this simple function to check if a value is in list:
template <class T>
bool IsinList(list<T> l, T x)
{
for(list<T>::iterator it=list.begin(); it != list.end(); it++)
{
if (*it == x)
return true;
}
return false;
}
I used the function in the same .cpp file like this:
if (!IsinList (words, temp))
goodwords.push_back(temp);
but I am getting this error :
'std::list' : use of class template requires template argument list
and I cant figure out what the problem is. I checked in previous asked questions and it didn't help.
Can you explain to me what am I doing wrong?

Typo there:
list.begin() / list.end()
should be
l.begin() / l.end()
Your variable is called l, not list.
EDIT:
As Martinho pointed out, this might not be enough. Some compilers will accept this, but since the iterator depends on the template argument, you might need a typename:
typename list<T>::iterator it=list.begin()

You made a typo (list vs. l) and did not specify that list<T>::iterator is a typename. Further, you should pass the list and the search argument by reference-to-const. All in all, it should look like this:
template <class T>
bool IsinList(const list<T>& l, const T& x)
{
typename list<T>::const_iterator first = l.begin(), last = l.end();
for(; first != last; ++first)
{
if (*it == x)
return true;
}
return false;
}
That said, still don't use this. Much better to use std::find instead
if (std::find(words.begin(), words.end(), temp)==words.end())
{
goodwords.push_back(temp);
}

Related

EXC Bad Access with Iterators

I created this function that works with vectors, linked lists and double linked lists. The function takes a value and searches for it in the container. If the vlaue is in the container than the function will insert the value right next to where it already exists. So, if val=2 then {3,2,5} will become {3,2,2,5}. But if the value does not exist in the container, it is added to the back instead.
I wrote this function using iterators. It works just fine with a vector, however when I try to run it with a list or double linked list I get an Exc Bad Access error at the line if (*it==val). I am not seeing what I did wrong.
template <class Container, class T>
void insertNextTo( Container &x, const T &val){
typename Container::iterator it = x.begin();
while (it!=x.end() && *it!=val){
++it;
}
if (*it == val){
x.insert(it, val);
}
else{
x.push_back(val);
}
}
Edit: Thank you everyone! Your suggestion to change the if statement worked perfectly!
Change
if (*it == val)
to:
if (it != x.end())
If val isn't found in the container, the loop will end when it == x.end(). That points past the end of the array, so indirecting through it results in undefined behavior.
If the value does not exist yet, it will be equal to end() when the loop is finished, and you cannot dereference end(). You need to change if (*it == val) to if (it != x.end()) instead:
//if (*it == val){
if (it != x.end()){
x.insert(it, val);
}
Alternatively, since you are only inserting one value, if you find val then you can do the insert() and exit the function immediately, and then push_back() only if the loop reaches the end of the container:
template <class Container, class T>
void insertNextTo( Container &x, const T &val ) {
typename Container::iterator it = x.begin();
while (it != x.end()) {
if (*it == val) {
x.insert(it, val);
return;
}
++it;
}
x.push_back(val);
}
In which case, you can simplify the code by using std::find() instead of a manual loop:
#include <algorithm>
template <class Container, class T>
void insertNextTo( Container &x, const T &val ) {
typename Container::iterator it = std::find(x.begin(), x.end(), val);
if (it != x.end()) {
x.insert(it, val);
} else {
x.push_back(val);
}
}
Or even this, since it is safe to insert() using the end() iterator, it is effectively the same as push_back():
template <class Container, class T>
void insertNextTo( Container &x, const T &val ) {
typename Container::iterator it = std::find(x.begin(), x.end(), val);
x.insert(it, val);
}
Someone correct me if I'm wrong but I believe your error comes from the fact that the when your iterator reaches the end of the list, it actually points to the address after the last bit of the list in memory, which may or may not be initialized and in scope, which causes your program to error.

Deduce iterator type in function template?

I'm trying to deduce the type of an iterator in a function which is already deducing the argument's type with a template. What I am trying to achieve is substitution for the keyword auto which has similar capability in C++11 standard. Originally I had the following function:
template<typename Type> bool activeExtension(Type &arr)
{
for (auto it=arr.begin(),
ite=arr.end();
it!=ite;
++it)
{
if (*it != 0)
return true;
}
return false;
}
This works perfectly compiling for C++11 standard. But things have changed and I cannot use such features anymore.
I am trying the achieve same functionally without the keyword auto. So I thought about the templates.
So far what I tried is this:
template<typename Type> bool activeExtension(Type &arr)
{
for (Type::iterator it=arr.begin(),
ite=arr.end();
it!=ite;
++it)
{
if (*it != 0)
return true;
}
return false;
}
How would you go to solve this?
Note:
I usually call this function with the following type,
template <class T>
struct Generic_t {
typedef std::vector<T> Array;
};
as I have to instantiate a vector with different types.
You should use typename Type::iterator since it's dependent-name.
Read more here

Declaring a generic iterator

I have the following problem: I need to make a function which takes two iterators and a value and checks if the value is found between the two. The catch: I can only have one template parameter which denotes the type of the elements from the iterators and the value.
My try is like this, but doesn't seem to work:
template <typename T>
T myFind(iterator<std::bidirectional_iterator_tag,T> begin, iterator<std::bidirectional_iterator_tag, T> end, T elem){
// Code
}
But this doesn't work then:
// vector<int> vect; list<string> lst;
myFind(vect.begin(), vect.end(), 15);
myFind(lst.begin(), lst.end(), "some element");
Any ideas?
Code after changes:
template <typename T>
T myFind(T begin, T end,typename std::iterator_traits<T>::value_type elem){
for(T it = begin; it != end; ++it){
if(*it == elem){
return it;
}
}
return end;
}
Can you have one template parameter that is the iterator type? If so:
template <typename It>
typename std::iterator_traits<It>::value_type
myFind(It begin, It end, typename std::iterator_traits<It>::value_type elem){
// ...
}
Otherwise, I think your restriction is too strong.
After your edit: If you want to do - on the iterator that is returned (as you show you do in the comments), you need a random access iterator. However, std::list::iterator is a bidirectional iterator so you can't. You will need to use std::prev (or in C++03, use std::advance).

Find index of iterator in STL container - need template function

I want to have a function with interface like this:
template<typename T, typename R> int find_index (const T& list, const R& value);
As I know, there is find() in STL that returns iterator. I need to return index of iterator (even for non-indexed containers such as std::list). I tried this code:
template<typename T, typename R>
int find_index (const T& list, const R& value)
{
int index = 0;
for (T::const_iterator it = list.begin(); it != list.end(); it++, index++)
if ((*it) == value)
return index;
return -1;
}
But compiler shows error on it - seems like it is not allowed to get const_iterator from templated typename. Can I go around it?
At the worst case I can pass begin and end iterators to find_index arguments, but it looks not so fine. Would be thankful for elegant solution.
for (typename T::const_iterator it = list.begin(); it != list.end(); ++it, ++index)
should solve your problem.
When using dependent types (types depending on template parameters), the compiler does not know that const_iterator is a type until it instantiates the template with a concrete type, it could also just be a static variable or whatever. Using the typename keyword, you tell him that const_iterator is really a type.
In C++11 you can also circumvent the whole typename issue using the auto keyword:
for (auto it = list.begin(); it != list.end(); ++it, ++index)
If you already have the iterator (maybe from some other operation), you can also just compute the distance from the list's begin to this iterator:
#include <iterator>
int index = std::distance(list.begin(), it);
But since this has linear complexity for a std::list, using your self-made find_index function is a better idea than std::find followed by std::distance, at least performance-wise.

How can i find a value in a map using binders only

Searching in the second value of a map i use somthing like the following:
typedef std::map<int, int> CMyList;
static CMyList myList;
template<class t> struct second_equal
{
typename typedef t::mapped_type mapped_type;
typename typedef t::value_type value_type;
second_equal(mapped_type f) : v(f) {};
bool operator()(const value_type &a) { return a.second == v;};
mapped_type v;
};
...
int i = 7;
CMyList::iterator it = std::find_if(myList.begin(), myList.end(),
second_equal<CMyList>(i));
Question: How can i do such a find in a single line without supplying a self written template?
Use a selector to select the first or the second element from the value_type that you get from the map.
Use a binder to bind the value (i) to one of the arguments of the std::equal_to function.
Use a composer to use the output of the selector as the other argument of the equal_to function.
//stl version
CMyList::iterator it = std::find_if(
myList.begin(),
myList.end(),
std::compose1(
std::bind2nd(equal_to<CMyList::mapped_type>(), i),
std::select2nd<CMyList::value_type>())) ;
//Boost.Lambda or Boost.Bind version
CMyList::iterator it = std::find_if(
myList.begin(),
myList.end(),
bind( &CMyList::mapped_type::second, _1)==i);
I am going to be off, voluntarily. The problem with lambda's is that (apart from C++0x) you cannot actually use something like _.second at the moment.
Personally, I thus use:
template <class Second>
class CompareSecond
{
public:
CompareSecond(Second const& t) : m_ref(t) {} // actual impl use Boost.callparams
template <class First>
bool operator()(std::pair<First,Second> const& p) const { return p.second == m_ref; }
private:
Second const& m_ref;
};
Which I combine with:
template <class Second>
CompareSecond<Second> compare_second(Second const& t)
{
return CompareSecond<Second>(t);
}
In order to get automatic type deduction.
And this way I can just write
CMyList::iterator it = std::find_if(myList.begin(), myList.end(), compare_second(i));
True, it does not use binders.
But at least, mine is readable and easily understandable, which beats the crap out of clever trickery in my opinion.
Note:
actually I went as far as wrapping STL algorithms to take full containers, so it would be:
CMyList::iterator it = toolbox::find_if(myList, compare_second(i));
which (imho) is clearly as readable as you can get without the auto keyword for type inference.
You can use Boost Lambda
CMyList::iterator it = std::find_if(
myList.begin(), myList.end(),
boost::lambda::bind(&CMyList::value_type::second, boost::lambda::_1) == i);
You can turn this problem around and just write your own algorithm and use it instead. This way you are not stuck with writing lots of little functors.
template <typename Iter, typename T>
Iter find_second(Iter first, Iter last, T value) {
while (first != last) {
if (first->second == value) {
return first;
}
++first;
}
return first;
}
Note this isn't tested or even compiled.
It seems to me that solving this with binders is just asking for lots of ugly code. What you are really asking for is a new algorithm so just add the algorithm. With that said, I would probably end up implementing something like Matthieu M. came up with.