passing list en list iterator as pointer c++ - c++

I am giving an list iterator pointer and a list pointer to a function. However I get the error:
error: no matching function for call to ‘SignalGrouper::DoesPeriodExist(std::__cxx11::list<wSignal>*, std::__cxx11::list<wSignal>::iterator&)’
if((DoesPeriodExist(&donePeriods,it2)==false) && it2->dTime < maxPeriod && it2->dTime > minPeriod)
function that calls pointer function:
std::list<std::list<wSignal>> SignalGrouper::groupByPeriod (std::list<wSignal> signals, int secs)
{
std::list<std::list<wSignal>> groupedSignals;
std::list<wSignal> donePeriods;
for (std::list<wSignal>::iterator it1=signals.begin(); it1 != signals.end(); ++it1)
{
if(DoesPeriodExist(&donePeriods,it1)==false) //check if period is already been grouped
{
boost::posix_time::ptime maxPeriod = boost::posix_time::ptime(it1->dTime);
boost::posix_time::ptime minPeriod = boost::posix_time::ptime(it1->dTime);
maxPeriod += boost::posix_time::seconds(secs/2);
minPeriod -= boost::posix_time::seconds(secs/2);
std::list<wSignal> oneSignalPeriod;
for (std::list<wSignal>::iterator it2=signals.begin(); it2 != signals.end(); ++it2)
{
if((DoesPeriodExist(&donePeriods,it2)==false) && it2->dTime < maxPeriod && it2->dTime > minPeriod) //check if period is already been grouped
{
oneSignalPeriod.push_back(*it2);
donePeriods.push_back(*it2);
}
}
groupedSignals.push_back(oneSignalPeriod);
}
}
return groupedSignals;
}
The pointer function:
bool SignalGrouper::DoesPeriodExist (std::list<wSignal>* signals, wSignal* s)
{
for (std::list<wSignal>::iterator it1=signals->begin(); it1 != signals->end(); ++it1)
{
if((it1->apNr == s->apNr) && (it1->MAC == s->MAC) && (it1->RSSI == s->RSSI) && (it1->dTime == s->dTime))
{
return true;
}
}
return false;
}
What am I doing wrong. How can I use the pointer function with pointers?

The function you are calling has the signature
bool SignalGrouper::DoesPeriodExist (std::list<wSignal>* signals, wSignal* s)
but on this line
DoesPeriodExist(&donePeriods,it1)
you are passing it
DoesPeriodExist (std::list<wSignal>* signals, std::list<wSignal>::iterator s)
To pass the correct type you could say
DoesPeriodExist(&donePeriods, &(*it1))

Related

Is there a simple way of refactoring this code?

I have a function that have very similar repeating code. I like to refactor it, but don't want any complex mapping code.
The code basically filter out columns in a table. I made this example simple by having the comparison statement having a simple type, but the real comparison can be more complex.
I am hoping there may be some template or lambda technique that can do this.
vector<MyRecord*>& MyDb::Find(bool* field1, std::string * field2, int* field3)
{
std::vector<MyRecord*>::iterator iter;
filterList_.clear();
std::copy(list_.begin(), list_.end(), back_inserter(filterList_));
if (field1)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field1 != *field1)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
if (field2)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field2 != *field2)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
if (field3)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field3 != *field3)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
return filterList_;
}
Update: Just in case someone is curious, this is my final code. Thanks again everyone. A lot easy to understand and maintain.
vector<MyRecord*>& MyDb::Find(bool* field1, std::string* field2, int* field3)
{
auto compare = [&](MyRecord* rec) {
bool add = true;
if (field1 && rec->field1 != *field1) {
add = false;
}
if (field2 && rec->field2 != *field2) {
add = false;
}
if (field3 && rec->field3 != *field3) {
add = false;
}
return add;
};
filterList_.clear();
std::copy_if(list_.begin(), list_.end(), back_inserter(filterList_), compare);
return filterList_;
}
you can use std::copy_if (as you already/would do a copy anyway)
vector<MyRecord*>& MyDb::Find(bool* field1, std::string* field2, int* field3){
filterList_.clear();
std::copy_if(list_.begin(), list_.end(), back_inserter(filterList_),[&](MyRecord* rec){
// whatever condition you want.
return field3 && rec->field3 != *field3;
});
return filterList_;
}
Is there a simple way of refactoring this code?
As far as I understood your algorithm/ intention, using std::erase_if (c++20) you can replace the entire while loops as follows (Demo code):
#include <vector> // std::erase_if
std::vector<MyRecord*> // return by copy as filterList_ is local to function scope
Find(bool* field1 = nullptr, std::string* field2 = nullptr, int* field3 = nullptr)
{
std::vector<MyRecord*> filterList_{ list_ }; // copy of original
const auto erased = std::erase_if(filterList_, [=](MyRecord* record) {
return record
&& ((field1 && record->field1 != *field1)
|| (field2 && record->field2 != *field2)
|| (field3 && record->field3 != *field3));
}
);
return filterList_;
}
If no support for C++20, alternatively you can use erase–remove idiom, which is in effect happening under the hood of std::erase_if.

I have template function. by using function std::for_each replace every positive number by biggest number from this container

template function gets 2 iterators, begin and end iterators.
template data type iterType is iterator type. I have error when trying to equate current iterator value to maximal value in lambda function right here:
[&](iterType* current) {if (current > 0) current = max; }
template<typename iterType>
void modify_each(iterType beg,iterType end) //3.3 #17
{
typename iterType::value_type max = *beg;
for (auto it = beg; it != end; it++)
{
if (max < *it) max = *it;
}
std::for_each(beg, end, [&](iterType* current) {if (current > 0) current = max; });
}
The member current is a pointer, therefore it probably always is bigger than zero.
Your lambda must accept iterator object and dereference it within the function. Try the following.
[&](iterType &current) {if (*current > 0) *current = max; });
The answer is:
template<typename iterType>
void modify_each(iterType beg,iterType end) //3.3 #17
{
typename iterType::value_type max = *beg;
for (auto it = beg; it != end; it++)
{
if (max < *it) max = *it;
}
std::for_each(beg, end, [=](typename iterType::value_type& current) {if (current > 0) current = max; });
}
Issue is that your lambda take wrong type.
You might do:
template<typename It>
void modify_each(It beg, It end) //3.3 #17
{
if (beg == end) return; // Empty range
const auto it = std::max_element(beg, end);
std::for_each(beg, end, [&](auto& current) { if (current > 0) current = *it; });
}
if you don't have generic lambda, you might use decltype(*beg) instead of auto&.
Alternatively, you might use type from std::iterator_traits<It>.

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).

Program crashing when trying to return a boolean

For this code my goal is to change some functions (more like modularize the program) so that any function that searches the database for a the memberNumber will call an actual search function which returns a boolean value.
Right now I'm already running into a problem with my program crashing whenever the searchID function returns true. When it returns false it doesn't crash.
Original working function:
bool DonorList::searchID(int memberNumber) const
{
bool found = false;
list<DonorType>::const_iterator iter = donors->begin();
while (iter != donors->end() && !found)
{
if (iter->getMembershipNo() == memberNumber)
{
found = true;
}
else
++iter;
}
return found;
}
Changed function:
bool DonorList::searchID(int memberNumber) const
{
list<DonorType>::const_iterator iter;
bool found = searchDonorLocation(memberNumber, iter);
return found;
}
Added function:
bool DonorList::searchDonorLocation(int memberNumber, list<DonorType>::const_iterator &iter) const
{
iter = donors->begin();
bool found = false;
while (iter != donors->end())
{
if (iter->getMembershipNo() == memberNumber)
{
found = true;
}
else
iter++;
}
return found;
}
I have no clue what is causing the issue other than that the program crashes whenever the newly changed function supposedly returns true. I've tried just returning searchDonorLocation(memberNumber, iter) but that causes the exact same crash.
while (iter != donors->end())
{
if (iter->getMembershipNo() == memberNumber)
{
found = true;
}
else
iter++;
}
When they match, your loop never ends because you don't bump your iterator so it can never get to the end. Is it crashing or hanging?
In your original code, you test for !found which exits the loop.
while (iter != donors->end() && !found)
Be careful that searchDonorLocation(..) doesn't exit the while loop if the condition is satisfied.
try:
while (iter != donors->end())
{
if (iter->getMembershipNo() == memberNumber)
{
found = true;
break;
}
else
iter++;
}

Parsing object inside array in rapidjson

I'm having problems implementing a recursive function that goes over the tree I get from the parsing of a json input.
json input. e.g.:
{
"attr" : { "a": 1, "ovec": [ { "b": 2, "c": 3 }, { "d": 4} ] }
}
This is what we call a 'compound value of an attribute', and the value is simply a JSON doc. Its content is completely arbitrary (as long as its valid JSON).
The problem is that with a Vector I have to loop using the type Value::ConstValueIterator (unlike for Object, where I use Value::ConstMemberIterator).
My recursive function has Value::ConstMemberIterator as parameter and all is OK until I encounter a Vector/Object inside a Vector - for the recursive call I'd need an iterator of the type Value::ConstMemberIterator.
Relevant parts of the "traversing" function:
int parseContextAttributeCompoundValue
(
const Value::ConstMemberIterator& node
)
{
std::string type = jsonParseTypeNames[node->value.GetType()];
if (type == "Array")
{
for (Value::ConstValueIterator iter = node->value.Begin(); iter != node->value.End(); ++iter)
{
std::string nodeType = jsonParseTypeNames[iter->value.GetType()];
if (nodeType == "String")
{
val = iter->GetString();
}
// else if ...
if ((nodeType == "Object") || (nodeType == "Array"))
{
// Here's my problem - need to convert 'iter' to Value::ConstMemberIterator
// in order to recursively call parseContextAttributeCompoundValue for this object/array
parseContextAttributeCompoundValue(iter); // COMPILATION ERROR
}
}
}
else if (type == "Object")
{
for (Value::ConstMemberIterator iter = node->value.MemberBegin(); iter != node->value.MemberEnd(); ++iter)
{
std::string nodeType = jsonParseTypeNames[iter->value.GetType()];
if (nodeType == "String")
{
val = iter->value.GetString();
}
else if (nodeType == "Number")
{
if ((nodeType == "Object") || (nodeType == "Array"))
{
// Here I'm just fine as iter is of the desired type already
parseContextAttributeCompoundValue(iter);
}
}
}
}
I've tried a few things like calling iter->value.MemberBegin() to "convert" to the desired type, but so far without any success
More than thankful for some help here ...
You can simply call a function with a Value type, instead of passing iterator:
void parseContextAttributeCompoundValue(const Value& v) {
if (v.IsObject()) {
// ...
}
else if (v.IsArray() {
// ...
}
}
And then from the calling site:
for (Value::ConstValueIterator iter = ...) {
parseContextAttributeCompoundValue(*iter);
}
for (Value::ConstMemberIterator iter = ...) {
parseContextAttributeCompoundValue(iter->value);
}