I'm having some troubles with using the std::sort algorithm here. I was reading that you can just overload the less than operator to sort classes, but I have been getting all sorts of errors. I have also tried using a functor as you can see in the example I made below.
I was hoping somebody could see what I'm doing wrong here.
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
class Thing {
public:
Thing(int val) {
this->_val = val;
}
bool operator<(Thing& rhs) {
std::cout << "this works!";
return this->val() < rhs.val();
}
int val() {
return this->_val;
}
protected:
int _val;
};
struct Sort {
bool operator()(Thing& start, Thing& end) {
return start.val() < end.val();
}
};
int main (int argc, char * const argv[]) {
std::srand(std::time(NULL));
std::vector<Thing> things;
for(int i = 0; i < 100; i++) {
Thing myThing(std::rand());
things.push_back(myThing);
}
if(things[1] < things[2]) {
//This works
}
//std::sort(things.begin(), things.end()); //This doesn't
//std::sort(things.begin(), things.end(), Sort()); //Neither does this
for(int i = 0; i < 100; i++) {
std::cout << things.at(i).val() << std::endl;
}
return 0;
}
Make your val() and operator<() const functions.
The same for Sort::operator() — take const Thing& instead of Thing&.
I believe you need to change
bool operator()(Thing& start, Thing& end) {
into
bool operator()(const Thing& start, const Thing& end) {
and
int val() {
into
int val() const {
IOW, your code needs to be const-correct and not claim it may modify things it in fact doesn't (nor needs to).
Try making operator< take its argument by const reference. You'll need to change its implementation to directly access _val or (preferably) make val() const as well when you do this (because a const member function can't call a non-const one).
Related
I have a program that I'm writing that has an abstract base class "AssortedSorted", a derived class "BubbleSort", and a a class to test sorts "AssortedSorterTest".
The Idea is to create a bubbleSort instance, pass that instance to an instance of assortedSorterTest along with an int for the quantity of random numbers to create and sort, and return true from assortedsorter.testSort() method if the vector is sorted and contains the same number of elements as the vector it was given.
If you read the code, there are things that need to be changed to accomplish this, but I'm not concerned with correcting those yet unless they are relevant to the issue I am currently having regarding invalid initialization on line 16 in main.cpp. The error that I am getting is this
"invalid initialization of non-const reference of type 'AssortedSorter&' from an rvalue of type BubbleSort*"
Initially I thought that adding #include "BubbleSort.h" to the AssortedSorterTest class may correct the problem, it did not. I've also tried changing some of the references to pointers, this created new problems for me, so I switched back to references. I haven't had any luck in figuring this out, so any healp would be appreciated.
#pragma once
#include <vector>
#include <string>
class AssortedSorter
{
public:
virtual std::vector<int> sort(const std::vector<int> &itemsToSort) = 0;
virtual std::string getName() const = 0;
virtual ~AssortedSorter() {};
};
#include <sstream>
class BubbleSort : public AssortedSorter
{
private:
long loopCount{0};
long swapCount{0};
public:
BubbleSort();
~BubbleSort() override;
std::vector<int> sort(const std::vector<int> &itemsToSort) override;
std::string getName() const override;
friend std::ostream &operator<<(std::ostream &out, const BubbleSort &rhs);
};
#include "BubbleSort.h"
BubbleSort::BubbleSort()
{
}
BubbleSort::~BubbleSort()
{
}
std::vector<int> BubbleSort::sort(const std::vector<int> &itemsToSort)
{
std::vector<int> itemsSorted = itemsToSort;
bool swap{false};
int temporary_num{};
do
{
swap = false;
for (int index = 0; index < itemsSorted.size()-1; index++)
{
loopCount++;
if (itemsSorted[index] > itemsSorted[index + 1])
{
swapCount++;
temporary_num = itemsSorted[index];
itemsSorted[index] = itemsSorted[index + 1];
itemsSorted[index + 1] = temporary_num;
swap = true;
}
}
} while (swap);
return itemsSorted;
}
std::string BubbleSort::getName() const
{return "BubbleSort";}
//Overloaded insertion operator
std::ostream &operator<<(std::ostream &os, const BubbleSort &rhs)
{
os << rhs.getName() << ": " << std::to_string(rhs.loopCount) << " " << std::to_string(rhs.swapCount);
return os;
}
#pragma once
#include "AssortedSorter.h"
#include <vector>
class AssortedSorterTest
{
public:
AssortedSorterTest();
~AssortedSorterTest();
bool testSort(AssortedSorter &assortedSorter, int size);
};
#include "AssortedSorterTest.h"
AssortedSorterTest::AssortedSorterTest()
{
}
AssortedSorterTest::~AssortedSorterTest()
{
}
bool testSort(AssortedSorter &assortedSorter, int size)
{
std::vector<int> randomNumbers;
for(int index{0}; index < size; index++)
{
randomNumbers.push_back(rand());
}
std::vector<int> sortedVector = assortedSorter.sort(randomNumbers);
if(sortedVector == randomNumbers)
{
return true;
}
else
{
return false;
}
}
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include "AssortedSorterTest.h"
#include "BubbleSort.h"
std::vector<int> assign_vector_values(int size);
int main()
{
std::vector<int> vec = assign_vector_values(100);
AssortedSorter &bubbleSort = new BubbleSort; //problem is here
AssortedSorterTest sortTester;
if(sortTester.testSort(bubbleSort, 100))
{
std::cout << "Vector has been sorted" << std::endl;
}
else
{
std::cout << "Vector has not been sorted properly" << std::endl;
}
delete bubbleSort;
return 0;
}
std::vector<int> assign_vector_values(int size)
{
std::vector<int> temp_vector;
for(int index{0}; index < size; index++)
{
temp_vector.push_back(rand());
}
return temp_vector;
}
The error message is telling you exactly what the issue is.
new BubbleSort results in a pointer to a BubbleSort.
You are trying to bind a reference to the base class of BubbleSort to it. That cannot work.
Either you need to dereference the pointer or you need to initialize a pointer, not a reference, with it.
In any case you should not use naked new/delete in modern C++. Use std::unique_ptr<AssortedSorter> and std::make_unique<BubbleSort>() instead:
std::unique_ptr<AssortedSorter> bubbleSort = std::make_unique<BubbleSort>();
This requires #include<memory>.
Or, given how exactly the code in main looks right now, there is no need for a dynamic allocation at all. Simply
BubbleSort bubbleSort;
will do as well.
So I'm using the STL priority_queue<> with pointers... I don't want to use value types because it will be incredibly wasteful to create a bunch of new objects just for use in the priority queue. So... I'm trying to do this:
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
private:
int m_val;
}
priority_queue<Int*> myQ;
myQ.push(new Int(5));
myQ.push(new Int(6));
myQ.push(new Int(3));
Now how can I write a comparison function to get those to be ordered correctly in the Q? Or, can someone suggest an alternate strategy? I really need the priority_queue interface and would like to not use copy constructors (because of massive amounts of data). Thanks
EDIT: Int is just a placeholder/example... I know I can just use int in C/C++ lol...
You can explicitly specify which comparator your queue should use.
#include <iostream>
#include <sstream>
#include <functional>
#include <vector>
#include <queue>
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
bool operator<(const Int &other) const { return m_val < other.m_val; }
private:
int m_val;
};
template<typename Type, typename Compare = std::less<Type> >
struct pless : public std::binary_function<Type *, Type *, bool> {
bool operator()(const Type *x, const Type *y) const
{ return Compare()(*x, *y); }
};
int main(int argc, char *argv[]) {
std::priority_queue<Int*, std::vector<Int*>, pless<Int> > myQ;
for (int i = 1; i < argc; i++) {
std::stringstream ss(argv[i]);
int x;
ss >> x;
myQ.push(new Int(x));
}
for (; !myQ.empty(); delete myQ.top(), myQ.pop())
std::cout << myQ.top()->getVal() << std::endl;
return 0;
}
One option that will surely work is to replace Int* with shared_ptr<Int> and then implement operator< for shared_ptr<Int>
bool operator<(const shared_ptr<Int> a, const shared_ptr<Int> b)
{
return a->getVal() < b->getVal();
}
An integer is the same size as a pointer on 32 bit systems. On 64 bit systems, a pointer will be twice as big. Therefore, it is simpler/faster/better to use regular integers.
#include <iostream>
#include <vector>
using namespace std;
//
// Below is what I want but not legal in current C++!
//
vector<int> operator ...(int first, int last)
{
vector<int> coll;
for (int i = first; i <= last; ++i)
{
coll.push_back(i);
}
return coll;
}
int main()
{
for (auto i : 1...4)
{
cout << i << endl;
}
}
I want to generate an integer sequence by using syntax 1...100, 7...13, 2...200 and the like.
I want to overload ... in C++.
Is it possible?
Is it possible?
No, it isn't possible.
... isn't an operator but a placeholder for variadic arguments.
There is no ... operator in C++, so you can't overload it.
However, you can use an ordinary name such as range.
Assuming a header that defines a suitable range function, your intended program
int main()
{
for (auto i : 1...4)
{
cout << i << endl;
}
}
… can then look like this:
#include <p/expressive/library_extension.hpp>
using progrock::expressive::range;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
for( auto i : range( 1, 4 ) )
{
cout << i << endl;
}
}
This is actual working code using the Expressive C++ library's range
implementation. However, that
library is currently in its very infant stages, in flux, with all kinds of
imperfections and fundamental changes daily. Also it implements an extended
dialect of C++, that is as yet unfamiliar to all but myself, so that posting the range implementation here where pure C++ is expected, would possibly/probably provoke negative reactions; I'm sorry. But you can easily translate that implementation to raw C++. It's Boost 1.0 license.
As mentioned in the other answers this is not possible since ... is not a valid operator, but in this language you can always create weird idioms like this:
#include <iostream>
struct int_it
{
int_it (int l, int r): left(l), right(r){}
void operator++() { left++;}
bool operator!=(const int_it& rhs) { return left != rhs.right;}
int operator*(){ return left;};
int left;
int right;
};
class range_op
{
public:
static range_op op() { return {0,0}; }
operator int() { return right - left; }
auto begin(){ return int_it{left, right}; }
auto end(){ return int_it{right,right}; }
private:
range_op(int l, int r): left(l), right(r){}
int left;
int right;
friend range_op operator*(int lhs, range_op r);
friend range_op operator*(range_op r, int rhs);
};
range_op operator*(int lhs, range_op r)
{
return range_op{lhs, r.right};
}
range_op operator*(range_op d, int rhs)
{
return range_op{d.left, rhs};
}
const auto o = range_op::op();
int main() {
for (int i : 2*o*6)
{
std::cout << i << std::endl;
}
return 0;
}
This is just a quick example, so no range checks and a lot of bugs.
I want to avoid code duplication as much as possible. Suppose I have a class such as,
class T {
int val;
bool operator < (const T& right) const { return val < right.val; }
}
I want to be able to call std::sort() like this,
std::sort( SomeContainer.begin(), SomeContainer.end(), FuncAdaptedFromOp );
This is my very first question in StackOverflow. Please be forgiving.
EDIT
The problem is that the class may have multiple bool T::Compare (const T& right) functions. I would still like an adapter. Take this example,
class Edge {
Vertex u, v;
bool CompareSrc (const Edge& right) const { return u < right.u; }
bool CompareDest (const Edge& right) const { return v < right.v; }
}
Sometimes I want to sort by source Vertex and sometimes by destination Vertex. I just want to know if this is possible or not.
If you don't provide a third parameter, then the < operator will be used.
http://www.cplusplus.com/reference/algorithm/sort/
"The elements are compared using operator< for the first version, and comp for the second."
using namespace std::placeholders;
std::sort(SomeContainer.begin(), SomeContainer.end()
// or use &Edge::CompareDest if you want that instead
, std::bind(&Edge::CompareSrc, _1, _2) );
std::bind is C++11 though, so you may want to use boost::bind (in which case you shouldn't use the preceding using directive) or the bind from TR1 if your implementation has that. Otherwise I'd advise you to handroll your own functor.
You just duplicate STL functor std::less http://www.cplusplus.com/reference/std/functional/less/
template <class T> struct less : binary_function <T,T,bool> {
bool operator() (const T& x, const T& y) const
{return x<y;}
};
Example with less:
#include <iostream>
#include <functional>
#include <algorithm>
struct my_struct {
int a;
bool operator< (const my_struct &s) const {
return a < s.a;
}
};
int main() {
my_struct array[10];
for (int i = 0; i < 10; ++i)
array[i].a = 10 - i;
std::sort(array, array + 10, std::less<my_struct>());
for (int i = 0; i < 10; ++i)
std::cout << array[i].a << ", ";
}
You don't need to write it.
Algorithm std::sort has two versions:
template <class RandomAccessIterator>
void sort ( RandomAccessIterator first, RandomAccessIterator last );
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
First version may be used when your class provides operator < (is comparable). Second version is used if you don't want use operator < or it doesn't exist.
Example without less:
#include <iostream>
#include <functional>
#include <algorithm>
struct my_struct {
int a;
bool operator< (const my_struct &s) const {
return a < s.a;
}
};
int main() {
my_struct array[10];
for (int i = 0; i < 10; ++i)
array[i].a = 10 - i;
std::sort(array, array + 10);
for (int i = 0; i < 10; ++i)
std::cout << array[i].a << ", ";
}
The examples have the same result.
Also you can use others functors to change behavior of sort algorithms such as std::greater.
So I'm using the STL priority_queue<> with pointers... I don't want to use value types because it will be incredibly wasteful to create a bunch of new objects just for use in the priority queue. So... I'm trying to do this:
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
private:
int m_val;
}
priority_queue<Int*> myQ;
myQ.push(new Int(5));
myQ.push(new Int(6));
myQ.push(new Int(3));
Now how can I write a comparison function to get those to be ordered correctly in the Q? Or, can someone suggest an alternate strategy? I really need the priority_queue interface and would like to not use copy constructors (because of massive amounts of data). Thanks
EDIT: Int is just a placeholder/example... I know I can just use int in C/C++ lol...
You can explicitly specify which comparator your queue should use.
#include <iostream>
#include <sstream>
#include <functional>
#include <vector>
#include <queue>
class Int {
public:
Int(int val) : m_val(val) {}
int getVal() { return m_val; }
bool operator<(const Int &other) const { return m_val < other.m_val; }
private:
int m_val;
};
template<typename Type, typename Compare = std::less<Type> >
struct pless : public std::binary_function<Type *, Type *, bool> {
bool operator()(const Type *x, const Type *y) const
{ return Compare()(*x, *y); }
};
int main(int argc, char *argv[]) {
std::priority_queue<Int*, std::vector<Int*>, pless<Int> > myQ;
for (int i = 1; i < argc; i++) {
std::stringstream ss(argv[i]);
int x;
ss >> x;
myQ.push(new Int(x));
}
for (; !myQ.empty(); delete myQ.top(), myQ.pop())
std::cout << myQ.top()->getVal() << std::endl;
return 0;
}
One option that will surely work is to replace Int* with shared_ptr<Int> and then implement operator< for shared_ptr<Int>
bool operator<(const shared_ptr<Int> a, const shared_ptr<Int> b)
{
return a->getVal() < b->getVal();
}
An integer is the same size as a pointer on 32 bit systems. On 64 bit systems, a pointer will be twice as big. Therefore, it is simpler/faster/better to use regular integers.