I organized two vectors of structures. Now I need to delete what is in chosen from points.
#include <StdAfx.h>;
#include <iostream>;
#include <vector>;
using namespace std;
struct SPoint
{
int id;
int X;
int Y;
};
vector<SPoint> points;
vector<SPoint> chosen;
void print_vect(const vector<SPoint> & vect)
{
for (int i = 0; i < vect.size(); ++i)
{
cout << vect[i].id << " (" << vect[i].X << "," << vect[i].Y << ")"<<endl;
}
cout << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
SPoint temp;
for (int i = 0; i < 10; i++)
{
temp.id = i;
temp.X = i;
temp.Y = i;
points.push_back(temp);
}
for (int i = 5; i < 10; i++)
{
temp.id = i;
temp.X = i;
temp.Y = i;
chosen.push_back(temp);
}
cout << "Points:" << endl;
print_vect(points);
cout << endl << endl;
cout << "Chosen:" << endl;
print_vect(chosen);
system("pause");
return 0;
}
There seems to be set_difference function. But the debugger tells me that I don't have a '<' method. It tells something like this:
error C2784: 'bool std::operator <(const std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'SPoint
I study procedural programming in C++. And I don't know what to do with this method. And it seems to me that it is impossible to do anything here with "<".
Could you help me execute the subtraction?
Yes, you have guessed correctly. The std::set_difference function needs the < operator to function. It uses it to check equality as (!a
The comparison to check for equivalence of values, uses either
operator< for the first version, or comp for the second, in order to
test this; The value of an element, a, is equivalent to another one,
b, when (!a<b && !b<a) or (!comp(a,b) && !comp(b,a)).
All you would need to do is to add a function like below
bool operator<(const SPoint& p1, const SPoint&p2){
return p1.id <p2.id;
}
Assuming your id field is a unique field. Now you will be able to use the std::set_difference function. This compares two SPoint variables by their id fields.
Note that BOTH ranges need to be sorted for it to work correctly.
You could use e.g. std::remove_if:
std::remove_if(std::begin(points), std::end(points), [](const SPoint& point) {
// Try to find the point in the `chosen` collection
auto result = std::find_if(std::begin(chosen), std::end(chosen),
[](const SPoint& p) {
return (p.id == point.id)
});
// Return `true` if the point was found in `chosen`
return (result != std::end(chosen));
});
Note that I use C++11 lambda functions in the above code.
Related
I want to use std::copy to copy an existing array of structures to new one. A regular option is fine with '''local_copy()'''. I want to know the procedure to use std::copy for such case described below -
I tried the code and get following error at compile time
#include <iostream>
class BigClass{
public:
struct Astruct{
double x[2], v[2];
int rank;
}one_struct;
};
void allocate(struct BigClass::Astruct& one_struct, int i)
{
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = i;
}
void local_copy(struct BigClass::Astruct& dest, struct BigClass::Astruct& source)
{
dest.x[0] = source.x[0];
dest.x[1] = source.x[1];
dest.v[0] = source.v[0];
dest.v[1] = source.v[1];
dest.rank = source.rank;
}
void print(struct BigClass::Astruct one_struct)
{
std::cout << one_struct.rank << " " << one_struct.x[0] << " " << one_struct.x[1] << " " << one_struct.v[0] << " " << one_struct.v[1] << "\n";
}
int main(int argc, char *argv[]) {
int size = 10;
struct BigClass::Astruct BCobj[size];
for(int i = 0; i < size; i++) allocate(BCobj[i], i);
for(int i = 0; i < size; i++) print(BCobj[i]);
struct BigClass::Astruct second_BCobj[size];
//for(int i = 0; i < size; i++) local_copy(second_BCobj[i], BCobj[i]); // this works
for(int i = 0; i < size; i++) std::copy(BCobj[i+1], BCobj[i], second_BCobj[i]); // not working
for(int i = 0; i < size; i++) print(BCobj[i]);
}
The compile time error is following -
/usr/include/c++/7/bits/stl_algobase.h:377:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::value_type _ValueTypeI;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:378:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:379:64: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::iterator_category _Category;
^~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:383:9: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
const bool __simple = (__is_trivial(_ValueTypeI)
~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_II>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_OI>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:386:44: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
return std::__copy_move<_IsMove, __simple,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_Category>::__copy_m(__first, __last, __result);
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
Some examples for vectors and int datatypes are available. Could anyone elaborate the appropriate sequence for std::copy for this kind of code structure?
Thanks.
std::copy is used instead of for loop, not with one.
std::copy(BCobj, BCobj + size, second_BCobj);
is essentially the same as
for(int i = 0; i < size; ++i) {
second_BCobj[i] = BCobj[i];
}
Also, don't forget to #include <algorithm> for std::copy
Explanation of arguments for std::copy:
std::copy takes as arguments 2 arguments of type matching InputIterator requirements and single argument of type OutputIteretor. Fortunately, pointers match these requirements, so we can use them directly. And because array name is interpreted as a pointer to its first element, we can pass it directly as argument to std::sort
Better version as suggested by Chef Gladiator:
std::copy(std::begin(BCobj), std::end(BCobj), std::begin(second_BCobj))
Welcome to Stack Overflow. You have presented your full code. Please next time also describe the development environment you are building in. Even better, try to present operating system agnostic and compiler agnostic, standard C++ code.
This is C++ forum, so we like to use standard C++ here. Your code is rewritten bellow using std::array. That makes it simple. Please study and enjoy the standard C++.
#include <array>
#include <iostream>
#include <algorithm>
namespace stack_overflow {
using namespace std;
struct BigClass final {
struct Astruct final {
double x[2], v[2];
int rank;
}one_struct;
friend ostream& operator << (ostream& os, Astruct const & one_struct)
{
return os << one_struct.rank << " " << one_struct.x[0] << " "
<< one_struct.x[1] << " " << one_struct.v[0] << " "
<< one_struct.v[1] ;
}
};
constexpr int size = 10;
using bcobj_arr = std::array<BigClass::Astruct, size>;
void populate( bcobj_arr& bcobjects_)
{
int j{ 0 };
for (auto& one_struct : bcobjects_) {
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = j++;
}
}
void print(const char prompt[BUFSIZ], bcobj_arr const & bcobjects_ )
{
cout << "\n\n" << prompt << "\n\n" ;
for (auto& one_struct : bcobjects_) {
cout << one_struct << "\n";
}
}
bool test (int argc, const char* argv[])
{
bcobj_arr BCobj;
populate(BCobj);
print("BCobj", BCobj);
// std::array instances can be copied
bcobj_arr second_BCobj = BCobj ;
print("second_BCobj", second_BCobj);
return true;
}
}
int main(const int argc, const char * argv[])
{
stack_overflow::test(argc, argv);
return 42;
}
Code is not commented at all. I assume you have a lot of questions, please do ask, in the comments bellow. I will try and answer them all by pointing you to the relevant documentation on-line.
Hey i have a table of teams with the names and the points they have and i'm trying to figure out how to display the last 3 teams with the least amount of points in the table?
It displays all the teams and i want it to display only the last 3 in the table but don't know what way to go about it.
These are my Accessors
string GetName
int GetPoints
int lowest = 1000;
for (int i = 0; i < numTeams; i++)
{
if (league[i].GetPoints() < lowest)
{
lowest = league[i].GetPoints();
}
}
for (int i = 0; i < numTeams; i++)
{
if (league[i].GetPoints() == lowest)
{
cout << "\tThe lowest goals against is: " << league[i].GetName() << endl;
}
}
Actually, you don't need variable lowest, if you would sort the data before printing.
#include <algorithm>
// Sort using a Lambda expression.
std::sort(std::begin(league), std::end(league), [](const League &a, const League &b) {
return a.GetPoints() < b.GetPoints();
});
int last = 3;
for (int i = 0; i < last; i++)
{
cout << "\tThe lowest goals against is: " << league[i].GetName() << endl;
}
U could probably start by sorting your array
#include <algorithm>
std::array<int> foo;
std::sort(foo.begin(), foo.end());
and then Iterate From Your Last Element to your Last - 3. (U can use Reverse Iterators)
for (std::vector<int>::reverse_iterator it = v.rend() ; it != v.rend() + 3;
it++) {
//Do something
}
or by using auto
for (auto it = v.rend() ; it != v.rend() + 3; ++it) {
//Do something
}
In my example I've created test class(TestTeam) to implement several important methods for objects in your task.
I use std::sort method to sort container of objects, by default std::sort compares objects by less(<) operation, so I have overrided operator < for TestTeam object
bool operator < ( const TestTeam& r) const
{
return GetPoints() < r.GetPoints();
}
Also we could pass as third parameter another compare method or lambda method as shown in below answers:
std::sort(VecTeam.begin(), VecTeam.end(), [](const TestTeam& l, const TestTeam& r)
{
return l.GetPoints() < r.GetPoints();
});
And example when we use global method to compare:
bool CompareTestTeamLess(const TestTeam& l, const TestTeam& r)
{
return l.GetPoints() < r.GetPoints();
}
//...
// some code
//...
// In main() we use global method to sort
std::sort(VecTeam.begin(), VecTeam.end(), ::CompareTestTeamLess);
You can try my code with vector as container:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
// Test class for example
class TestTeam
{
public:
TestTeam(int16_t p, const std::string& name = "Empty name"):mPoints(p), mName(name)
{
};
int16_t GetPoints() const {return mPoints;}
const std::string& GetName() const {return mName;}
void SetName( const std::string& name ) {mName=name;}
bool operator < ( const TestTeam& r) const
{
return GetPoints() < r.GetPoints();
}
private:
int16_t mPoints;
std::string mName;
};
int main(int argc, const char * argv[])
{
const uint32_t COUNT_LOWEST_ELEMENTS_TO_FIND = 3;
// Fill container by test data with a help of non-explicit constructor to solve your task
std::vector<TestTeam> VecTeam {3,5,8,9,11,2,14,7};
// Here you can do others manipulations with team data ...
//Sort vector by GetPoints overloaded in less operator. After sort first three elements will be with lowest points in container
std::sort(VecTeam.begin(), VecTeam.end());
//Print results as points - name
std::for_each( VecTeam.begin(), VecTeam.begin() + COUNT_LOWEST_ELEMENTS_TO_FIND, [] (TestTeam el)
{
std::cout << el.GetPoints() << " - " << el.GetName() << std::endl;
} );
}
I made test class TestTeam only to implement test logic for your object.
If you try launch the program you can get next results:
2 - Empty name
3 - Empty name
5 - Empty name
Program ended with exit code: 0
A few answers here (How to loop through a boost::mpl::list? being the one I started with) imply that I should be able to construct a generic lambda to feed to a boost::mpl::for_each() but I'm unable to find a working example, or build one myself.
Idealy what I would like to be able to do in a lambda is take a function like
template<typename T>
void TestFunction(const int &p)
{
T t(p);
std::cout << "p = " << p << ", t = " << t << std::endl;
};
that I'm currently calling in a loop with something like
for(int k = 0; k < 2; ++k)
{
TestFunction<int>(k);
TestFunction<long>(k);
TestFunction<float>(k);
TestFunction<double>(k);
};
and replace it with something like
typedef boost::mpl::list<int, long, float, double> ValidTypes;
for(int k = 0; k < 2; ++k)
{
// lambda definition that captures k
// boost::mpl::for_each(ValidTypes, ...) that calls the lambda.
};
Is this possible? If not with for_each() with one of the other mpl constructs? I've got a version of the code running where I overload operator() but I'd like to see a lambda solution if it's possible.
Thanks,
Andy.
If you can use C++14's generalized lambdas, you can capture the value of p and also infer the type of the current valid type being passed to the lambda:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
int main()
{
using ValidTypes = boost::mpl::list<int, long, float, double>;
for (auto k = 0; k < 2; ++k) {
boost::mpl::for_each<ValidTypes>([p = k](auto arg) {
using T = decltype(arg);
T t(p);
std::cout << "p = " << p << ", t = " << t << '\n';
});
}
}
Live Example.
Edit: for extra credit, here's a slightly more advanced version that also works for non-default constructible types:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
class NonDefaultConstructible
{
int value;
public:
NonDefaultConstructible(int const& p) : value(p) {}
friend auto& operator<<(std::ostream& ostr, NonDefaultConstructible const& ndc)
{
return ostr << ndc.value;
}
};
int main()
{
using ValidTypes = boost::mpl::list<int, long, float, double, NonDefaultConstructible>;
for (auto k = 0; k < 2; ++k) {
boost::mpl::for_each<ValidTypes, boost::mpl::make_identity<boost::mpl::_1>>([p = k](auto arg) {
using T = typename decltype(arg)::type;
T t(p);
std::cout << "p = " << p << ", t = " << t << '\n';
});
}
}
Live Example.
For an explanation of the somewhat convoluted use of make_identity, see my very first Q&A here!
I have a map which has a class as key.
In this class I overloaded the < operator, I read here that the map will automatically use that for comparison and sorting.
I get the following error when compiling:
Error 1 error C2664: 'std::pair::pair(const
std::pair &)' : cannot convert argument 1 from
'Position' to 'Position *const &' e:\program files\visual studio 2013
ultimate\vc\include\xmemory0
I don't get what that really means or how I can avoid it. It doesn't highlight anything in my code either.
Here is my code, my class is coordinates, I want them to be sorted from left to right and top to bottom, but the logic isn't the problem here.
There's obviously more stuff in the Position files, but I think these are the relevant parts.
main.cpp
int main()
{
std::map<Position*, int> karte;
Position p1;
p1.setX(0);
p1.setY(0);
Position p2;
p2.setX(0);
p2.setY(1);
Position p3;
p3.setX(1);
p3.setY(0);
Position p4;
p4.setX(1);
p4.setY(1);
karte.emplace(p1, 1);
karte.emplace(p2, 2);
karte.emplace(p3, 3);
karte.emplace(p4, 4);
for (auto& x : karte)
{
std::cout << x.first->toString() << ": " << x.second << std::endl;
}
return 0;
}
Position.h
bool operator<(const Position&) const;
Position.cpp
bool Position::operator<(const Position &position) const
{
if ((x_ < position.x_) && (y_ == position.y_))
{
return true;
}
if (x_ > position.x_ && y_ < position.y_)
{
return true;
}
if (x_ == position.x_ && y_ < position.y_)
{
return true;
}
else
{
return false;
}
}
If you need the map's keys to be pointers, you can create your own comparator and pass it to the map:
struct PositionPointerLesser
{
bool operator() (Position *lhs, Position *rhs) const
{
return *lhs < *rhs; // This calls the operator < in your class
}
};
int main()
{
std::map<Position*, int, PositionPointerLesser> karte;
// ...
}
Redefine your map as:
std::map<Position, int> karte;
The compilation error is because you're trying to insert a pair<Position, int> into the map:
Position p1;
<snip>
karte.emplace(p1, 1);
and you've declared your map as map<Position*, int>
Is it possible to create an STL-like container, or even just an STL-style iterator, for an existing array of POD-type elements?
For example, suppose I have an array of ints. It would be convenient to be able to call some of the STL functions, such as find_if, count_if, or sort directly on this array.
Non-solution: copying the entire array, or even just references to the elements. The goal is to be very memory- and time-saving while hopefully allowing use of other STL algorithms.
You can call many of the STL algorithms directly on a regular C style array - they were designed for this to work. e.g.,:
int ary[100];
// init ...
std::sort(ary, ary+100); // sorts the array
std::find(ary, ary+100, pred); find some element
I think you'll find that most stuff works just as you would expect.
You can use an inline function template so that you don't have to duplicate the array index
template <typename T, int I>
inline T * array_begin (T (&t)[I])
{
return t;
}
template <typename T, int I>
inline T * array_end (T (&t)[I])
{
return t + I;
}
void foo ()
{
int array[100];
std::find (array_begin (array)
, array_end (array)
, 10);
}
All the STL algorithms use iterators.
A pointer is a valid iterator into an array of objects.
N.B.The end iterator must be one element past the end of the array. Hence the data+5 in the following code.
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
int data[] = {4,3,7,5,8};
std::sort(data,data+5);
std::copy(data,data+5,std::ostream_iterator<int>(std::cout,"\t"));
}
You can use Boost.Array to create a C++ array type with STL semantics.
using arrays:
int a[100];
for (int i = 0; i < 100; ++i)
a[i] = 0;
using boost.arrays:
boost::array<int,100> a;
for (boost::array<int,100>::iterator i = a.begin(); i != a.end(); ++i)
*i = 0;
Update: With C++11, you can now use std::array.
A pointer is a valid model of an iterator:
struct Bob
{ int val; };
bool operator<(const Bob& lhs, const Bob& rhs)
{ return lhs.val < rhs.val; }
// let's do a reverse sort
bool pred(const Bob& lhs, const Bob& rhs)
{ return lhs.val > rhs.val; }
bool isBobNumberTwo(const Bob& bob) { return bob.val == 2; }
int main()
{
Bob bobs[4]; // ok, so we have 4 bobs!
const size_t size = sizeof(bobs)/sizeof(Bob);
bobs[0].val = 1; bobs[1].val = 4; bobs[2].val = 2; bobs[3].val = 3;
// sort using std::less<Bob> wich uses operator <
std::sort(bobs, bobs + size);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
// sort using pred
std::sort(bobs, bobs + size, pred);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
//Let's find Bob number 2
Bob* bob = std::find_if(bobs, bobs + size, isBobNumberTwo);
if (bob->val == 2)
std::cout << "Ok, found the right one!\n";
else
std::cout << "Whoops!\n";
return 0;
}