I try to sort a structure but I have this error :
error: cannot convert ‘std::vector<Node>’ to ‘void*’ for argument ‘1’ to ‘void qsort(void*, size_t, size_t, __compar_fn_t)’
qsort(nodes,nodes.size(), sizeof(Node), dataClustering::compare);
This is my code :
compare function :
int compare(const void * node1, const void * node2){
string name1 = ((const struct Node*)node1)->name;
string name2 = ((const struct Node*)node2)->name;
int start1 = ((const struct Node*)node1)->start;
int start2 = ((const struct Node*)node2)->start;
if(name1 <= name2 && start1 <= start2){
return -1;
}
else if(name1 > name2 && start1 > start2){
return 1;
}
else{
return 0;
}
}
Call of compare in another function :
qsort(allNodes,allNodes.size(), sizeof(Node), compare);
And the header in .hpp file (I try to put it in static but this don't solve the error):
int compare(struct Node *, struct Node *);
You can pass vector to C-style sort, for example, like this:
qsort(&allNodes[0], allNodes.size(), sizeof(Node), compare);
You would be better off using std::sort, which works with vectors natively:
bool compareNodes(const Node& lhs, const Node& rhs) {
return (lhs.name < rhs.name)
|| (lhs.name == rhs.name && lhs.start < rhs.start);
}
...
std::sort(allNodes.begin(), allNodes.end(), compareNodes);
in C++11/C++14 you can define comparison as a lambda, too:
std::sort(allNodes.begin(), allNodes.end(), [] (const auto& lhs, const auto& rhs) {
return (lhs.name < rhs.name)
|| (lhs.name == rhs.name && lhs.start < rhs.start);
});
(the code above uses auto for lambda arguments, a C++14 feature).
The error is that you
cannot convert ‘std::vector<Node>’ to ‘void*’
and thus, a std::vector<Node> cannot possibly be a suitable first argument to a function like qsort with signature
void (void*, size_t, size_t, __compar_fn_t)
While there are things you could do to use qsort here, you really shouldn't: you should use std::sort from the C++ standard library:
using std::sort;
sort(begin(allNodes), end(allNodes), compare_function);
Here, compare_function should be a function that acts like < and takes two arguments of the appropriate type (e.g. the actual type of the objects you're sorting or const references to them, not pointers to them or void pointers) and returns bool if the first argument is less than the second. (compare_function doesn't actually have to be a function: it can also be any object that has an appropriate operator() or a lambda)
If you want to just sort, use
#include <algorithm>
...
bool myfunction (const Node &lhs, const Node &lhs) {
if(lhs.name < rhs.name) return true;
return (lhs.name == rhs.name && lhs.start < rhs.start));
}
...
std::sort(allNodes.begin(), allNodes.end(), compare_func);
Further read: std::sort
If you want to use cstyle qsort(which I suggest you should not), add a wrapper function to do the conversion of void * to Node * and change the first argument of qsort to static_cast<void *>(&allNodes[0])
Related
MSVS 16.9.3
Win7-64
I get an invalid comparator error on the second execution of my sort comparator passed to the C++ Sort function provided in <algorithm>. I don't understand why I am getting this error! The sort routine call is:
sort(sorted.begin(), sorted.end(), remsort);
sorted is defined like this:
vector<ADI::RDA_Asset*>& sorted = *(new vector<ADI::RDA_Asset*>);
These are the three versions of remsort that I used:
Version 1: always works:
bool HOAReports::remsort(ADI::RDA_Asset* lhs, ADI::RDA_Asset* rhs) {
return (lhs->getRem() < rhs->getRem());
};
Version 2: works on the first call to remsort by the sort routine, fails on the second:
bool HOAReports::remsort(ADI::RDA_Asset* lhs, ADI::RDA_Asset* rhs) {
return ( (lhs->getRem() < rhs->getRem())
|| ((lhs->getCatName()).compare(rhs->getCatName()) < 0)
|| ((lhs->getRDAName()).compare(rhs->getRDAName()) < 0)
};
Version 3: works on the first call to remsort by the sort routine, fails on the second:
bool HOAReports::remsort(ADI::RDA_Asset* lhs, ADI::RDA_Asset* rhs) {
bool return_value = ( (lhs->getRem() < rhs->getRem())
|| ((lhs->getCatName()).compare(rhs->getCatName()) < 0)
|| ((lhs->getRDAName()).compare(rhs->getRDAName()) < 0)
);
return return_value;
};
Version 2/3 have the same functionality. On the first and second call to remsort only ((lhs->getRem() < rhs->getRem()) is executed and the return_value is true. Looking at the failed assertion, it looks like the assertion is checked on both calls but fails on the second.
The MSVS code which fails is:
// FUNCTION TEMPLATE _Debug_lt_pred
template <class _Pr, class _Ty1, class _Ty2,
enable_if_t<is_same_v<_Remove_cvref_t<_Ty1>, _Remove_cvref_t<_Ty2>>, int> = 0>
constexpr bool _Debug_lt_pred(_Pr&& _Pred, _Ty1&& _Left, _Ty2&& _Right) noexcept(
noexcept(_Pred(_Left, _Right)) && noexcept(_Pred(_Right, _Left))) {
// test if _Pred(_Left, _Right) and _Pred is strict weak ordering, when the arguments are the cv-same-type
const auto _Result = static_cast<bool>(_Pred(_Left, _Right));
if (_Result) {
_STL_VERIFY(!_Pred(_Right, _Left), "invalid comparator");
}
return _Result;
}
Your comparison function does not fulfill the strict weak ordering requirements. See C++ named requirements: Compare.
In your specific case, you could implement it like this:
bool HOAReports::remsort(ADI::RDA_Asset* lhs, ADI::RDA_Asset* rhs) {
if(lhs->getRem() < rhs->getRem()) return true;
if(rhs->getRem() < lhs->getRem()) return false;
// if we get here, lhs.getRem() == rhs.getRem()
auto cmp = lhs->getCatName().compare(rhs->getCatName());
if(cmp) return cmp < 0;
// if we get here, lhs->getCatName() == rhs->getCatName()
return lhs->getRDAName() < rhs->getRDAName();
}
Demo
Or simpler, use std::tuple or std::tie:
#include <tuple>
bool HOAReports::remsort(ADI::RDA_Asset* lhs, ADI::RDA_Asset* rhs) {
return
std::tuple{lhs->getRem(), lhs->getCatName(), lhs->getRDAName()}
<
std::tuple{rhs->getRem(), rhs->getCatName(), rhs->getRDAName()};
}
I'm programming in QtCreator and currently I'm using QList as shown in the following code:
#include <vector>
#include <map>
#include <algorithm>
#include <QDebug>
class mixed
{
public:
int number;
QString name;
QString address;
mixed(int n, QString s, QString a)
{
number = n;
name = s;
address = a;
}
};
bool myfunction (mixed i,mixed j) { return (i.number<j.number); }
bool mySearch (mixed i, mixed j) {
return (i.name==j.name);
}
int main()
{
QList<mixed>myV;
mixed object(100, "akkas", "100");
myV.push_back(object);
myV.push_back(mixed(2, "akkas1", "2"));
myV.push_back(mixed(1111, "akkas2", "1111"));
myV.push_back(mixed(-1, "akkas3", "-1"));
myV.push_back(mixed(7, "akkas4", "7"));
myV.push_back(mixed(0, "akkas0", "0"));
myV.push_back(mixed(2, "akkas0", "21"));
for(int i=0; i<myV.size(); i++)
{
qDebug()<<myV.at(i).number<<" "<<myV.at(i).name<<" "<<myV.at(i).address<<endl;
}
std::sort (myV.begin(), myV.end(), myfunction);
for(int i=0; i<myV.size(); i++)
{
qDebug()<<myV.at(i).number<<" "<<myV.at(i).name<<" "<<myV.at(i).address<<endl;
}
// QList<mixed>::iterator it;
// it = std::search(myV.begin(), myV.end, object, mySearch);
// if (it!=myV.end())
// qDebug() << "found at position " << (it-myV.begin()) << '\n';
// else
// qDebug() << "not found\n";
// qDebug()<<myV.indexOf(object)<<endl;
return 0;
}
But the problem is the commented out line
qDebug()<<myV.indexOf(object)<<endl;
fails because
no match for 'operator==' (operand types are 'mixed' and 'const mixed')
if (n->t() == t)
^
On the other hand I was trying to use std::search using predicate comparison where predicate is as below:
bool mySearch (mixed i, mixed j) {
return (i.name==j.name);
}
But I can't understand why it gives the error
no matching function for call to 'search(std::vector<mixed>::iterator, <unresolved overloaded function type>, mixed&, bool (&)(mixed, mixed))'
it = std::search(myV.begin(), myV.end, object, mySearch);
^
I need to use something that can allow me easy sorting using the integer value of the mixed data type and finding any element using the string value of that type.
What mistake am I doing in my approach? What alternative do I have? Could you please give me some example with code?
Thanks.
EDIT
After the responses I have corrected end to end(), but even then there are errors. Now the error is:
error: no matching function for call to 'search(QList<mixed>::iterator, QList<mixed>::iterator, mixed&, bool (&)(mixed, mixed))'
std::search(myV.begin(), myV.end(), object, mySearch);
^
qDebug()<<myV.indexOf(object)<<endl;
For this to work you need to implement == operator for class mixed. Example:
bool operator==(const mixed& rhs)
{
return name == rhs.name;
}
For second error, As rightly pointed out in the comments, you need to correct end iterator.
std::search(myV.begin(), myV.end(), object, mySearch);
^^^^^^^^
UPDATE: However this is NOT correct use of std::search. Use std::search which relies on == operator.
std::find(myV.begin(), myV.end(), object); // Uses == operator to find match
Reference: http://www.cplusplus.com/reference/algorithm/find/
This should work.
For cases like this, where your find criterion may differ from call to call, I prefer find_if: it does not force me to overload operator== for my type.
auto it = std::find_if(begin(myVec), end(myVec),
[](const auto &a, const auto &b) { return a.name == b.name; });
auto index = std::distance(begin(myVec), it);
struct HASH_CMP {
bool operator()(vector<int> V, vector<int> W) const {
for(int i = 0; i < 10; i++)
if(V[i] != W[i]) return false;
return true;
}
};
hash_map< std::vector<int>, int, HASH_CMP > H;
long long inHash(const vector<int> &V) {
if(H.find(V) == H.end()) return -1; //this line
return H[V];
}
I have declared the following hash, given the comparing class above and I receive an error at the line mentioned saying:
no match for call to '(const HASH_CMP) (const std::vector<int, std::allocator<int> >&)
I need some help on fixing this code.
The third template argument is the hash functor. The comparison functor is the fourth template argument. Thus you need:
hash_map<std::vector<int>, int, HASH_HASH, HASH_CMP>
And you still need to write HASH_HASH.
(I recommend you look at Boost's hash_range implementation for inspiration.) Also note that equality for vectors is already defined (and more efficiently than your version) and shouldn't require self-written code.
As the error is telling you, you need a hashing function that takes a const std::vector<int>& and returns a size_t. To put something in a hash map, there has to be some way to hash it.
This will work:
size_t operator()(const vector<int>& vec)
{
size_t v = 0;
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
v = (v ^ *it) * 0x9e3779b9;
return v;
}
I created a struct that contains information about variables, namely their name and number
struct var{
string name;
int value;
};
Now, I want to use iterators to update it, using the following function:
void updateVariable(vector<Variable>& vars,Variable& newVar){
vector<Variable>::iterator it = find(vars.begin(), vars.end(), newVar);
if(it == vars.end()){
vars.push_back(newVar);
}
else{
*it = newVar;
}
}
Just to be sure, the error I'm getting is at the line with the call to find(). Any ideas why I'm getting the error? Here is the error:
/usr/include/c++/4.6/bits/stl_algo.h:162:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = Variable*, _Container = std::vector<Variable>, __gnu_cxx::__normal_iterator<_Iterator, _Container>::reference = Variable&]() == __val’
Update:
Thank you guys for all the quick help, and the clear answers!
You haven't defined operator == for your var struct. The find() algorithm by default will use operator == to compare the value you provide with the values in the specified range, and return the iterator to the first element which compares equal.
To fix this, just overload operator == for your class. One way to do that is this:
struct var
{
string name;
int value;
};
bool operator == (var const& v1, var const& v2)
{
return (v1.name == v2.name) && (v1.value == v2.value);
}
Make sure you define operator == in the same namespace as your var structure, otherwise ADL (Argument Dependent Lookup) will fail and you will likely get a compiler error.
If you are working with C++11 and you do not want to bother defining an overloaded version of operator ==, you can even use find_if() and pass a lambda as the last argument:
find_if(vars.begin(), vars.end(), [&] (var const& v) {
return (v.name == newVar.name) && (v.value == newVar.value);
});
As GManNickG correctly points out, when you need to compare several members, using std::tie and the overloaded operator == for std::tuple may save you some typing:
auto const tieMembers = [] (const var&) {
return std::tie(v.name, v.value, ...);
};
The above lambda can then be used this way when comparing values v1 and v2 of type var:
return (tieMembers(v1) == tieMembers(v2));
You need to define an overload of operator== for var. This should work.
bool operator==(const var& a, const var& b){
return (a.name == b.name) && (a.value == b.value);
}
I have defined a class like this
using namespace std;
class foo {
public:
typedef std::pair< int, int > index;
bool operator == ( const index &l, const index &r )
{
return (l.first == r.first && l.second == r.second);
}
void bar()
{
index i1;
i1.first = 10;
i1.second = 20;
index i2;
i2.first = 10;
i2.second = 200;
if (i1 == i2)
cout << "equal\n";
}
};
However I get this error in windows
error C2804: binary 'operator ==' has too many parameters
and this error in linux
operator==(const std::pair<int, int>&, const std::pair<int, int>&)’ must take exactly one argument
I found this topic overloading operator== complaining of 'must take exactly one argument' and seems to be a problem with static and non-static functions in a class. However I don't know how to apply this
For example, this is not correct
bool operator == ( const index &r )
{
return (this->first == r.first && this->second == r.second);
}
How can I fix that?
The operator== can be implemented in two ways:
As member function: in this case, the function takes one argument and is invoked on the left operand which is passed as this pointer implicitly to the function.
As non-member function, in which case, the function takes two arguments, left and right operands.
Since you're implementing operator== for std::pair, you cannot implement it as member function (of std::pair). The option you're left with is non-member function.
So implement it outside the class as:
bool operator==(std::pair<int,int> const & l, std::pair<int,int> const & r)
{
return (l.first == r.first && l.second == r.second);
}
But then you don't really need to implement it yourself unless you want to implement it differently. The Standard Library has already provided a generic version of operator== for std::pair which lexicographically compares the values in the pair, like I did above, i.e compare first with first and second with second. If you need to compare them differently, only then provide your own specific definition (non-template version).
The above mentioned points are worth noting as to how to implement operator== when you need it for your defined types.
You need to move operator== out of class foo:
bool operator == ( const foo::index &l, const foo::index &r )
{
return (l.first == r.second && l.second == r.second);
}
class foo {
public:
typedef std::pair< int, int > index;
void bar()
{
index i1;
i1.first = 10;
i1.second = 20;
index i2;
i2.first = 10;
i2.second = 200;
if (i1 == i2)
cout << "equal\n";
}
};
Also note, std::pair has overload operator== already, see: link, you might reconsider if necessary to write your own again.
If you overload the == operator inside a class, it should only take a single parameter so that comparison can be done between the current object and the argument.
You can move that operator out of the class, that way you can take 2 operands. Indeed there is no point of keeping it within the class at this point, since you are only comparing member variables and not the class itself.
Indeed I wont be surprised if pair already defines the operator you write.
Edit : Yup It looks like pair already implements this
Two pair objects are compared equal if the first elements in both objects compare equal to each other and both second elements also compare equal to each other - they all have to match.
p.s. I think you meant
return (l.first == r.first && l.second == r.second);
^^^^^^