Reverse Iterator Arithmetic - c++

All, I'm trying to do an O(n^2) comparison between elements in a list in reverse, so I'm using a reverse iterator.
Code follows
#include <list>
struct Element {
double a;
double b;
};
typedef std::list<Element> ElementList;
class DoStuff {
public:
DoStuff();
void removeDuplicates(ElementList & incList) const {
for(ElementList::reverse_iterator stackIter = incList.rbegin(); stackIter != incList.rend(); ++stackIter) {
bool uniqueElement = true;
for(ElementList::reverse_iterator searchIter = stackIter+1; searchIter != incList.rend() && uniqueElement; ++searchIter) {
//Check stuff and make uniqueElement = true;
}
}
}
};
int main() {
std::list<Element> fullList;
DoStuff foo;
foo.removeDuplicates(fullList);
}
I get a compile error on the searchIter creation... why...
This works, but its stupid to read:
ElementList::reverse_iterator searchIter = stackIter;
searchIter++;
for( ; searchIter != incList.rend() && uniqueElement; ++searchIter) {
}
Error below:
In file included from /usr/local/include/c++/6.1.0/bits/stl_algobase.h:67:0,
from /usr/local/include/c++/6.1.0/list:60,
from main.cpp:1:
/usr/local/include/c++/6.1.0/bits/stl_iterator.h: In instantiation of 'std::reverse_iterator<_Iterator> std::reverse_iterator<_Iterator>::operator+(std::reverse_iterator<_Iterator>::difference_type) const [with _Iterator = std::_List_iterator<Element>; std::reverse_iterator<_Iterator>::difference_type = long int]':
main.cpp:16:66: required from here
/usr/local/include/c++/6.1.0/bits/stl_iterator.h:233:41: error: no match for 'operator-' (operand types are 'const std::_List_iterator<Element>' and 'std::reverse_iterator<std::_List_iterator<Element> >::difference_type {aka long int}')
{ return reverse_iterator(current - __n); }

The syntax it + n for some iterator it and integer n requires the iterator to be a "random access iterator". List iterators do not fulfill that requirement.
To get around the "stupid to read" issue, you can use std::next:
for(ElementList::reverse_iterator searchIter = std::next(stackIter); ...
Or, with less typing:
for(auto searchIter = std::next(stackIter); ...

Related

Am I using find wrong?

I'm trying to find string tp inside an unordered_map but it's giving me problems.
unordered_map < string, int > pastPoints;
int t = 0;
void doStuff(int x, int y) {
pair < int, int > tp_ = {x, y};
string tp = int_string(tp_);
if (find(pastPoints.begin(), pastPoints.end(), tp) != pastPoints.end()) {
ans = max(ans, t - pastPoints[tp]);
}
pastPoints[tp] = t;
}
It's giving me this error:
error: no match for ‘operator==’ (operand types are ‘std::pair<conststd::basic_string<char>, int>’ and ‘const std::basic_string<char>’)
{ return *__it == _M_value; }
Am I using unordered_map::find wrong? I'm finding the key which is a string.
Yes, you're using it wrong.
Don't use std::find with maps and sets. It will check the elements one by one, while maps/sets have a faster way to search for elements.
Do this: pastPoints.find(tp).
Also using pastPoints[tp] after a successful find is wasteful, since it searches the map again. Instead, dereference the iterator returned by find.
Example:
if (auto it = pastPoints.find(tp); it != pastPoints.end())
ans = max(ans, t - *it);

How to use arma::vec as key in std::map

I've implemented the following code to update a Markov model but the compiler doesn't allow me to use an armadillo vector as key in a std::map. Any ideas?
typedef std::vector<std::map<arma::vec, int>> vmaps_t;
struct markov
{
uint8_t maxord;
vmaps_t m_maps;
std::vector<char> m_chars;
markov(uint8_t maxord)
{
m_maps = vmaps_t(maxord);
}
void update(const arma::vec &v)
{
for (size_t ord = 0; ord < maxord; ord++)
{
if (v.n_elem > ord)
{
if (std::find(m_chars.begin(), m_chars.end(), v.back()) == m_chars.end()) //just to tell elem not in vect...
{
m_chars.push_back(v.back());
}
arma::vec seq = v.rows(v.n_rows - ord, v.n_rows - 1);
if (m_maps[ord].find(seq) == m_maps[ord].end())
{
m_maps[ord][seq] = 0;
}
m_maps[ord][seq]++;
}
}
}
};
error: cannot convert ‘arma::enable_if2, arma::Col, arma::glue_rel_lt> >::result {aka const arma::mtGlue, arma::Col, arma::glue_rel_lt>’ to ‘bool’ in return
{ return __x < __y; }
To use anything as a key in a std::map you need that "anything" to implement a operator<. That operator needs to implement a strict weak ordering for elements.
If the class you are working with does not currently implement such an operator it cannot be a map key. The solution is to add/implement such an operator.

binary '==': no operator found which takes a left - hand operand of type 'std::pair<const _Kty,_Ty>'

This error is pretty common but none of the solutions I have seen worked for me.
The solutions I have seen were with other types of operands instead of pair but that shouldn't be an excuse.
What I understand in the error is that I have not defined the equal operator with pairs, but I am not comparing pairs at any moment, I am always working with the key or the value.
#include "cabezeras.h"
using namespace std;
int main()
{
string x;
ifstream inFile;
bool t2, t3;
int times2 = 0, times3 = 0;
map<char, int> mymap;
map<char, int>::iterator it;
pair<char, int> aux_pair;
inFile.open("C:/Users/victor/source/repos/AdventOfCode2018/Day2/input.txt");
if (!inFile) {
cout << "Unable to open file";
exit(1);
}
while (getline(inFile, x)) {
t2 = false, t3 = false;
mymap.clear();
for (int i = 0; i < x.length(); i++) {
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
}
it = mymap.begin();
int valor;
while (it != mymap.end()) {
if (valor == 2) {
t2 = true;
}
if (valor == 3) {
t3 = true;
}
it++;
}
if (t2) {
times2++;
}
if (t3) {
times3++;
}
}
inFile.close();
cout << "Val = " << times2 * times3 << endl;
}
When debbuging(it takes me to xutility file):
template<class _InIt, class _Ty> inline
_InIt _Find_unchecked1(_InIt _First, const _InIt _Last, const _Ty& _Val, false_type)
{ // find first matching _Val
for (; _First != _Last; ++_First)
if (*_First == _Val) // THIS IS THE LINE OF THE ERROR
break;
return (_First);
}
Instead of using std::find you should be using std::map::find, so replace this
it = find(mymap.begin(), mymap.end(), x[i]);
with
it = mymap.find(x[i]);
You way over-complicated your code:
for (int i = 0; i < x.length(); i++) {
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
}
should be instead:
for (int i = 0; i < x.length(); i++)
mymap[ x[i] ]++;
or even shorter using for range loop:
for (char c : x ) mymap[c]++;
std::map::operator[] is specially designed for cases like this and you can find it in example code of the documentation.
You still have lots of C habits, forget about them.
The map iterator has a const for its first member, that's what the error message is telling you:
auto it = mymap.find(x[i]);
or if you don't have C++11
map<const char, int>::iterator it = mymap.find(x[i]);
But don't declare all your variables at the beginning, loose this habit, declare them where you need them at the appropriate scope.
When you need another it after, use another auto, and probably worth changing the name for something more descriptive.
But as Slava said, the default initializer for map says, you can do:
for (char c : x ) ++mymap[c];
This piece of code:
it = find(mymap.begin(), mymap.end(), x[i]);
if (it == mymap.end()) {
aux_pair = make_pair(x[i], 1);
mymap.insert(aux_pair);
}
else {
it->second++;
}
Could be replaced by
auto insert_pair = mymap.insert({x[i], 0});
++*insert_pair.first->second;
The insert function returns a std::pair with an iterator as the first value and a boolean indicator as the second.
If the insertion failed, because the key x[i] already exists, the iterator in first will be an iterator to the existing element pair. If the insertion succeeded, then the first will be an iterator to the newly inserted element pair.
Since I insert the data value 0, if the insertion was successful then increasing the value will make it 1 (which is what you insert). And if it fails because the key already exist, then we increase the existing value (like you do).

C++ vector - find ("no match for 'operator =='")

So I'm pretty new to C++, so I wanted to loop through a multidimensional vector that I have, but I'm getting errors such as
stl_algo.h
error: no match for 'operator==' (operand types are std::vector<std::basic_string<char> >' and 'const std::basic_string<char>'
There is lots of errors, here is the code:
mClass.h
std::vector<std::vector<std::string> > aData;
mClass.cpp
bool mClass::checkVector(std::string k)
{
if (std::find(mClass::aData.begin(), mClass::aData.end(), k) != mClass::aData.end())
{
return true;
}
return false;
}
mClass::aData.begin() and mClass.aData.end() return iterators over vectors, not iterators over strings. There is no operator == to compare a vector and a string. Hence the error.
You'll need to iterate through the vectors. Assuming you have C++11 support:
bool mClass::checkVector(std::string const& k)
{
for (auto const& vec : aData) { // Each `vec` is a std::vector<std::string>
for (auto const& str : vec) { // Each `str` is a std::string
// compare string represented by it2
if (str == k) {
return true;
}
}
}
return false;
}
The (pre-c++11) solution is to iterate through the vectors first:
Note the typedef for convenience.
typedef std::vector<std::vector<std::string> > vvec;
bool mClass::checkVector(std::string k)
{
for(vvec::const_iterator it=mClass::aData.begin(), end=mClass::aData.end();it!=end;++it){
const std::vector<std::string>& inner=*it;
if (std::find(inner.begin(), inner.end(), k) != inner.end())
{
return true;
}
}
return false;
}
Because you have a multidimensional array you can't use an iterator to go through every value so the best way to do it is to make a loop first
for(std::vector<std::vector<std::string> >::iterator it = Class::aData.begin(); it!=mClass::aData.end(); ++it)
if (std::find(it->begin(), it->end(), k) != it->end())
{
return true;
}
return false;
You can use std::find only on the lowest level of iterator, not on an iterator on a full vector.

C++ vector containing pointers of user-defined types

I have a problem with this code:
struct document_type_content
{
long long m_ID;
QString m_type_name;
};
std::vector<QString> document_type::get_fields_by_name(e_doc_type) const
{
std::vector<QString> tmp;
std::vector<document_type_content*>::iterator it = m_table_data.begin(),
it_end = m_table_data.end();
for ( ; it != it_end; ++it) {
document_type_content* cnt = *it;
tmp.push_back(cnt->m_type_name);
}
}
I'm using QtCreator for the project and it's gave me the following error(for lines, where the iterator is being initialized):
error: conversion from '__gnu_cxx::__normal_iterator<document_type_content* const*, std::vector<document_type_content*, std::allocator<document_type_content*> > >' to non-scalar type '__gnu_cxx::__normal_iterator<document_type_content**, std::vector<document_type_content*, std::allocator<document_type_content*> > >' requested
This may be simple problem, anyway, not to me:).
Great thanks in advance.
Because your function is constant, you only have constant access to the this pointer of your class. The results in a constant access to your vector. You need to get a const_iterator from the vector.
This should do the trick:
std::vector<QString> document_type::get_fields_by_name(e_doc_type) const
{
std::vector<QString> tmp;
std::vector<document_type_content*>::const_iterator it = m_table_data.begin(),
it_end = m_table_data.end();
for ( ; it != it_end; ++it) {
document_type_content* cnt = *it;
tmp.push_back(cnt->m_type_name);
}
}