I am trying to create a set of function pointers in c++ but getting error while inserting / deleting elements from it.
#include<bits/stdc++.h>
using namespace std;
void func(int x) {
cout<<x;
}
int main() {
set <function<void (int)>> mine;
mine.insert(func);
return 0;
}
i am getting error
/usr/include/c++/6/bits/stl_function.h:386:20: error: no match for ‘operator<’ (operand types are ‘const std::function’ and ‘const std::function’).
I think that this problem is because of operator that will be used to compare set values , can someone suggest how to make this work ?
How can i write a comparator for function pointers in this case ?
If you want to store just function pointers, you don't need std::function:
using MyFunctionPointer = void(*)(int);
void func(int x);
std::set<MyFunctionPointer> orderedSet;
int main()
{
orderedSet.emplace(func);
}
Demo
This works because you can compare (for std::set) or hash (for std::unordered set) function pointer values. But comparing or hashing std::function instances is not implemented in the standard library, and there is no portable way to add that after the fact.
Edit: As pointed out by #HolyBlackCat, while the builtin operator< is not required to induce the required total order on function pointers, std::less (as used by std::set) is required to do so for any pointer.
Related
For finding pairs in a vector, I am using unordered_set. I need help in why the creation is not working.
I am working on some code trying to find the pairs in a vector. I needed unordered_set for the logic.
Here is my code:
int sockMerchant(int n, vector<int> ar) {
set<int> colors = new unordered_set<int>();
int pairs;
for ( int i = 0 ; i < n ; i++ ) {
if(!colors.contains(ar[i])) {
colors.insert(ar[i]);
} else {
pairs++;
colors.erase(ar[i]);
}
}
return pairs;
}
Error message:
Solution.cpp: In function 'int sockMerchant(int, std::vector<int>)':
Solution.cpp:10:23: error: conversion from 'std::unordered_set<int>*' to non-scalar type 'std::set<int>' requested
set<int> colors = new unordered_set<int>();
^~~~~~~~~~~~~~~~~~~~~~~~
Solution.cpp:15:20: error: 'class std::set<int>' has no member named 'contains'
if(!colors.contains(ar[i])) {
^~~~~~~~
Exit Status
1
I except the unordered_set to be created and contains to be used.
There are a lot of issues here (and the compiler is nice enough to be really informative about it)
You're trying to assign std::unordered_set<int>* into a std::set<int> variable. The types don't match, one is a pointer (returned from new()) and the other is a local stack variable. The actual classes don't match either unordered_set != set
std::set nor std::unordered_set does not have a member function named contains (at least not in the current C++ standard, will be available in C++20). You can just use the find member function from within std::unordered_set to see if an element is already in the set.
You can have a look on the definition of the class in here:
https://en.cppreference.com/w/cpp/container/unordered_set
In another note, if there is no need to use new, don't use it. The function does not return the set that you created.
If you insist of using new, you should use delete after you finish using the set, if you won't do that you will have memory leaks.
I don't understand why I can't have an unordered_map with an array<int,3> as the key type:
#include <unordered_map>
using namespace std;
int main() {
array<int,3> key = {0,1,2};
unordered_map< array<int,3> , int > test;
test[key] = 2;
return 0;
}
I get a long error, the most pertinent part being
main.cpp:11:9: error: no match for ‘operator[]’ (operand types are std::unordered_map<std::array<int, 3ul>, int>’ and ‘std::array<int, 3ul>’)
test[key] = 2;
^
Are arrays not eligible to be keys because they miss some requirements?
You have to implement a hash. Hash tables depending on hashing the key, to find a bucket to put them in. C++ doesn't magically know how to hash every type, and in this particular case it doesn't know how to hash an array of 3 integers by default. You can implement a simple hash struct like this:
struct ArrayHasher {
std::size_t operator()(const std::array<int, 3>& a) const {
std::size_t h = 0;
for (auto e : a) {
h ^= std::hash<int>{}(e) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}
};
And then use it:
unordered_map< array<int,3> , int, ArrayHasher > test;
Edit: I changed the function for combining hashes from a naive xor, to the function used by boost for this purpose: http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html. This should be robust enough to actually use.
Why?
As mentioned in http://www.cplusplus.com/reference/unordered_map/unordered_map/
Internally, the elements in the unordered_map are not sorted in any
particular order with respect to either their key or mapped values,
but organized into buckets depending on their hash values to allow for
fast access to individual elements directly by their key values (with
a constant average time complexity on average).
Now as per your question we need to hash an array which has not been implemented internally in standard c++.
How to get over with it?
So if you want to map an array to a value you must implement your own std::hash http://en.cppreference.com/w/cpp/utility/hash for which you might get some help from C++ how to insert array into hash set?.
Some work around
If you are free to use boost then it can provide you with hashing of arrays and many other types. It basically uses hash_combine method for which you can have a look at http://www.boost.org/doc/libs/1_49_0/boost/functional/hash/hash.hpp.
The relevant error is
error: no match for call to '(const std::hash<std::array<int, 3ul> >) (const std::array<int, 3ul>&)'
The unordered_map needs a hash of the key, and it looks for an overload of std::hash to do that. You can extend the namespace std with a suitable hash function.
Compiled with msvc14 gives the following error:
"The C++ Standard doesn't provide a hash for this type."
I guess this is self-explanatory.
I understand a set is ordered, thus adding an object without overloading the < operator doesn't allow to say which object is smaller to keep the container sorted. However, I don't understand why this isn't possible with an unordered_set.
If I try something like this:
#include <iostream>
#include <string
#include <unordered_set>
struct someType{
string name;
int code;
};
int main(){
std::unordered_set <someType> myset;
myset.insert({"aaa",123});
myset.insert({"bbb",321});
myset.insert({"ccc",213});
return 0;
}
I get a couple of errors like:
c:\qt\qt5.1.0\tools\mingw48_32\lib\gcc\i686-w64-mingw32\4.8.0\include\c++\bits\hashtable_policy.h:1070: error: invalid use of incomplete type 'struct std::hash'
c:\qt\qt5.1.0\tools\mingw48_32\lib\gcc\i686-w64-mingw32\4.8.0\include\c++\bits\functional_hash.h:58: error: declaration of 'struct std::hash'
error: no matching function for call to 'std::unordered_set::unordered_set()'
c:\qt\qt5.1.0\tools\mingw48_32\lib\gcc\i686-w64-mingw32\4.8.0\include\c++\bits\hashtable_policy.h:1103: error: no match for call to '(const std::hash) (const someType&)'
c:\qt\qt5.1.0\tools\mingw48_32\lib\gcc\i686-w64-mingw32\4.8.0\include\c++\bits\stl_function.h:208: error: no match for 'operator==' (operand types are 'const someType' and 'const someType')
Why is that and how can I fix it?
To use type in unordered_set or unordered_map you need hashing function for your type. For common types, like int or std::string - hashing function is provided by standard library. For your type, you can overload standard std::hash, like this:
namespace std {
template <> struct hash<someType> {
size_t operator()(const someType & x) const {
std::hash<std::string> h;
return h(x.name);
// or simply return x.code
// or do something more interesting,
// like xor'ing hashes from both members of struct
}
};
}
Another way is to provide your own type with overloaded operator() and put it as hash template argument in unordered_set, like this:
struct someTypeHasher {
size_t operator()(const someType& x) const {
return x.code;
}
};
std::unordered_set<someType, someTypeHasher> myset;
Good reading for theory about hash based containers is here
Also, do not forget, that you need to overload operator== for someType, without it - it will also not work.
As explained in the answer given by Starl1ght, you need to provide a hash function for someType. However, I would combine all members of your class by that hash function. Otherwise, you might get a lot of collisions, for example, if the same name occurs very often, but with different code values. For creating a hash function, you can make use of Boost, but you can also handcraft it.
Starl1ght also mentioned that you need to overload operator== for someType,
but you can also define a separate comparison function instead and provide it to the unordered_set. Moreover, you can use lambda expressions instead of defining the hash and comparison functions. If you put everything together, then your code could be written as follows:
auto hash = [](const someType& st){
return std::hash<std::string>()(st.name) * 31 + std::hash<int>()(st.code);
};
auto equal = [](const someType& st1, const someType& st2){
return st1.name == st2.name && st1.code == st2.code;
};
std::unordered_set<someType, decltype(hash), decltype(equal)> myset(8, hash, equal);
Code on Ideone
What I am trying to do is:
#include <QVector>
#include <QLinkedList>
#include <QSet>
class MyType
{
//...
};
int main(int argc, char** argv)
{
QVector<MyType> vector;
QSet<QVector<MyType>::iterator> a;
a.insert(vector.begin()); // This is fine
QLinkedList<MyType> linkedList;
QSet<QLinkedList<MyType>::iterator> b;
b.insert(linkedList.begin()); // This does not compile
return 0;
}
The compiler message is:
error: no matching function for call to 'qHash(const QLinkedList<MyType>::iterator&)'
I know, that the reason why the first three lines compile is that for the QVector, the iterator is defined as typedef T* iterator; but for the QLinkedList it is a custom type.
I found out, that the QSet template class is implemented in terms of a hash table.
Apparently it is possible to evaluate the hash function for a pointer, but not for a custom type.
Please, could you tell me, how to overload the qHash function for my program to compile? I have read some basic information on the workings of a hash table, but I lack the confidence in the subject.
I tried to understand the inner workings of the QLinkedList<T>::iterator. It seems that it is very similar to the QVector<T>::iterator. It just holds a pointer to a node in the linked list instead of a pointer to the item itself.
class iterator
{
public:
...
Node *i;
...
};
So I tried to define the function in this manner:
uint qHash(QLinkedList<MyType>::iterator it)
{
return qHash(it.i);
}
The program compiled, but I have no confidence in my solution. How should I correctly overload the qHash function?
You did perfectly well already. The basic rules of hash functions are:
If x = y then hash(x) = hash(y).
If x != y then hash(x) != hash(y) (as often as possible). This isn't a strict rule, but the better it's followed, the better the performance of the hash table. Ideally, the outputs will appear random.
Your way works because if two iterators, ia and ib are equal (referring to the same node), their internal pointers, ia.i and ib.i will be equal. That takes care of rule 1. Then you use a built-in hash function on those pointers; Qt takes care of rule 2 for you.
Cheers!
I want to sort a vector using std::sort, but my sort method is a static method of a class, and I want to call std::sort outside it, but it seems to be trouble doing it this way.
On the class:
static int CompareIt(void *sol1, void *sol2) { ... }
std::sort call:
sort(distanceList.at(q).begin(),
distanceList.at(q).end(),
&DistanceNodeComparator::CompareIt);
Shouldn't it be possible to do this way?
std::sort takes a comparator that accepts value of the type held in the collection and returns bool. It should generally implement some notion of <. E.g., assuming your distanceList elements have collections of integers (I assume they don't, but for the sake of the example):
static bool CompareIt(int sol1, int sol2) { ... }
And of course you only need to supply a comparator if there isn't already a < operator that does the right thing for your scenario.
It should be a boolean method (sort uses operator <() by default to compare values)
The comparison function you've provided has the signature of the one needed by qsort, which is the sorting function that C provided before C++ came along. sort requires a completely different function.
For example if your declaration of distanceList is std::vector<DistanceNode> your function would look like:
static bool CompareIt(const DistanceNode &sol1, const DistanceNode &sol2)
{
return sol1.key < sol2.key;
}
Notice that sorting a std::list with the standard sort algorithm isn't efficient, which is why list supplies its own sort member function.
As others have mentioned, it needs a boolean return type. Here's an example which works:
#include "stdafx.h"
#include <vector>
#include <algorithm>
using namespace std;
class MyClass
{
public:
static bool CompareIt(const void *a1, const void *a2)
{
return a1 < a2;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// Create a vector that contains elements of type MyData
vector<void*> myvector;
// Add data to the vector
myvector.push_back((void*)0x00000005);
myvector.push_back((void*)0x00000001);
// Sort the vector
std::sort(myvector.begin(), myvector.end(), MyClass::CompareIt);
// Display some results
for( int i = 0; i < myvector.size(); i++ )
{
printf("%d = 0x%08X\n", i, myvector[i] );
}
return 0;
}
[Edit] Updated the code above to make it a little simpler. I'm not suggesting it's nice code, but without know more about the OPs real implementation, it's difficult to give a better example!
First, the return type should be bool. Actually the requirement is only that the return type be assignable to bool, which int is. But the fact that you're returning int suggests that you might have written a three-way comparator instead of the strict weak ordering required by std::sort.
Your CompareIt function takes two void* pointers as parameters. Is distanceList.at(q) a vector<void*> (or vector of something convertible to void*)? If not, then the comparator inputs aren't right either. Using void* with algorithms also suggests that you're doing something wrong, because much of the point of generic programming is that you don't need opaque pointers that later get cast back to their original type.