I'm currently having a problem with a class template in C++. I'm currently making a hash table.
I'm using a functor as a class template to specify my hash function for each instance of a table.
IE: one table has integers for its keys, strings for its values. Another could have strings for its keys and integers for its values, etc...
class HashString
{
public:
unsigned long operator()(std::string& key, const unsigned int tableSize)
{
// .....
}
};
template<typename keyType, typename valueType, class HashFunctor>
class HashTable
{
public:
// ....
private:
HashFunctor myHash;
};
And now let's say I want to call the method called "myHash" to hash a key, I would at first call it by doing:
myHash(key, table.size())
But gcc doesn't find a function overload for HashFuntor(string, unsigned int) for example.
Could someone tell me how I could call myHash?
(Note: I would not like to change my structure of functors)
edit: This is the error message I get from my actual solution
instantiated from ‘void tp3::Table<TypeClef, TypeDonnee, FoncHachage>::insert(const TypeClef&, const TypeDonnee&) [with TypeClef = int, TypeDonnee = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, FoncHachage = tp3::HacheString]’
no match for call to ‘(tp3::HacheString) (tp3::Table<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, tp3::HacheString>::HashEntry&)’
Edit: Everywhere it says HacheString is in fact HashString (I've translated my code to paste it here).
operator() in HashString is private and is probably not const-correct. It should be a const member function taking const std::string& as its first parameter. The second parameter does not need to be const.
You seem to be calling it with HashEntry as the second parameter. What is HashEntry? It takes an unsigned int!
That might already solve some of your problems.
I assume your HacheString / HashString difference is just a typo.
Related
I am a beginner of C++, and I code what The Cherno teaches in his 100th video of the C++ series, showing at 16:50. But VS is always giving me error.
If without commenting the const part, VS gives me error c3848. After adding const, VS give me error c2676.
I have checked the way to use std::hash on cppreference, and searched for the error on Google, but get nothing. It's just "a little bit" too hard for a beginner like me.
Below is the code.
#include<iostream>
#include<map>
#include<unordered_map>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
};
namespace std {
template<>
struct hash<CityRecord>
{
size_t operator()(const CityRecord& key) //const noexcept
{
return hash<std::string>()(key.Name);
}
};
}
int main()
{
std::unordered_map<CityRecord, uint32_t> foundedMap;
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
As a beginner, I just want to know how to use the hash function in this case.
There is a much easier solution, without opening the std namespace and specializing the std::hash
If you look at the definition of the std::unordered_map in the CPP reference here, then you will read:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
It is clear and normal, to hand in template parameters for the key-type and the value-type value. However, if the key-type if a custom type, like in your case, then you need to add additional functionality.
First, you need to add hash functionionality. If you read here about std::hash, then the only function the will be called is the "function call operator".
And this must be a "const" function, which will fix one of your problems.
And of course, you may add this function to your struct. That is completely OK. Please see in the example code below. With taht, you can give your own class as a template parameter for the hash functionality to the std::unordered_map. Cool.
If we look at the next template parameter of the std::unordered_map, then we will find std::equal_to. And if we read about this in cppreference, then we will find the following statement:
Function object for performing comparisons. Unless specialised, invokes operator== on type T.
So, we need to add a comparison operator == to your custom struct to satisfy requirements.
Please note: It is a good approach to encapsulate the methods operating on the data of classes within the class and not define them as free functions. Because only the methods of the class should work on the data of the class. If you would later change something in a class and have a free function doing work on the class members. So, please try to follow that approach.
Then, next, the comparison. So, we define the "operator ==" in your class and then have to compare element by element.
For easing up this task, there is a library function called std::tie. Please see here. This basically creates a std::tuple from the given parameters with the advantage, that all comparison functions are already defined and can be immediately reused.
By following the above described approach, the whole implementation will be much simpler.
Please see the below example code:
#include<iostream>
#include<map>
#include<unordered_map>
#include<tuple>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
// For std::equal_to
bool operator == (const CityRecord& cr) const { return std::tie(Name, Population, Latitude, Longtitude) == std::tie(cr.Name, cr.Population, cr.Latitude, cr.Longtitude); }
// For hashing
size_t operator()(const CityRecord& key) const { return std::hash<std::string>{}(key.Name); }
};
int main() {
// Definition of the unordered_map
std::unordered_map<CityRecord, uint32_t, CityRecord> foundedMap;
// Adding data
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
You need to make the overloaded operator() for the specialization of hash for CityRecord a const member function as shown below. Additionally, we also need to overload operator== for CityRecord as shown below:
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
//friend declaration for operator== not needed since we've a struct
};
//implement operator==
bool operator==(const CityRecord &lhs, const CityRecord &rhs)
{
return (lhs.Name == rhs.Name) && (lhs.Population == rhs.Population) && (lhs.Latitude ==rhs.Latitude) && (lhs.Longtitude == rhs.Longtitude);
}
namespace std {
template<>
struct hash<CityRecord>
{
//-----------------------------------------------vvvvv-->added this const
size_t operator()(const CityRecord& key) const
{
return hash<std::string>()(key.Name) ^ hash<uint64_t>()(key.Population) ^ hash<double>()(key.Latitude) ^ hash<double>()(key.Longtitude);
}
};
}
Working demo
Here we use an (unnamed) hash<string> object to generate a hash
code for Name, an object of type hash<uint64_t> to generate a hash from Population, and an object of type hash to generate a hash from Latitute and finally an object of type hash<double> to generate a hash from Longitute. Next, we exclusive OR these results to form an overall hash code for the given CityRecord object.
Note that we defined our hash function to hash all the four data members so that our hash function will be compatible with our definition of operator== for CityRecord.
I have an issue on returning an item from a std::map residing inside a class.
I am trying to create a simple function like
ExplorerObjectMapItem* MyClass::getFirst()
{
mInternalMapIterator = mObserverLookup.begin();
ExplorerObjectMapItem* item = &*mInternalMapIterator;
return item;
}
where the following typedefs are used
typedef map< Subject*, shared_ptr<ExplorerObject> > ExplorerObjectMap;
typedef pair<Subject*, shared_ptr<ExplorerObject> > ExplorerObjectMapItem;
typedef ExplorerObjectMap::iterator ExplorerObjectIter;
and the map and iterator are class members:
ExplorerObjectMap mObserverLookup;
ExplorerObjectIter mInternalMapIterator;
The above code for the getFirst() function gives a compile error saying
E2034 Cannot convert 'pair<Subject * const,boost::shared_ptr<ExplorerObject>
> *' to 'ExplorerObjectMapItem *'
Not sure what is going on here. Any help appreciated.
A std::map<K,V> does not contain std::pair<K,V> objects. It contains std::pair<const K, V> objects. That missing const is what throws off the conversion.
You could fix this with either
typedef pair<Subject* const, shared_ptr<ExplorerObject> > ExplorerObjectMapItem;
or
typedef ExplorerObjectMap::value_type ExplorerObjectMapItem;
This code compiles successfully with VS, but when porting it to Linux and compiling with g++ it errors out.
template <class Key, class Value>
void Dictionary<Key, Value>::set(const Key &key, Value value)
{
typename Dictionary<Key,Value>::iterator i = this->find(key);
if (i == this->end())
{
access(&key, &value, eINSERT);
this->insert(value_type(key, value));
}
else
{
access(&key, &i->second, eCLEAR);
dispose(i->second);
access(&key, &value, eSET);
i->second = value;
}
}
template <class Key, class Value> class PtrDictionary : public Dictionary<Key, Value>;
class Processor
{
private:
ptrdictionary<const string,const type*> m_Types;
void Processor::add(const string name, const Type* t)
{
if (m_Types.get(name))
error("Type '"+string(name)+"' already defined", eParseError);
m_Types.set(name, t); // this is where the error is received
}
}
The error is:
../Packages/Dictionary.h: In instantiation of 'void Dictionary::set(const Key&, Value) [with Key = const
std::basic_string; Value = const AsmLoader::Type*]':
Instructions.cpp:94:21: required from here
../Packages/Dictionary.h:79:37: error: expected primary-expression
this->insert(value_type(key, value));
Update:
value_type is an object in std::map, and all it took for g++ to compile the code was to add this:
typedef typename map<const Key, Value>::value_type value_type;
Thanks everyone for your comments, this is my first time using SO and this is a very complex code so I forgot to specify this part...
Unfortunately, it does not look as if this can be implemented in the same fashion as in VS. In researching this, I found:
Can dictionaries be used in c++
They suggested using std::map in STL as a similar method in C++ (without .NET). In case the above link changes, here is a quote from the answer supplied:
There is a corresponding type in STL, that's called std::map.
It has the same basic functionality as a .NET Dictionary, but the
implementation is quite different. std::map is internally based on a
red-black tree datastructure, while Dictionary uses a hash table
internally.
If you're just looking for something with the same behaviour, std::map
will do, but if you have large amounts of data you have to be aware of
the different performance characteristics.
** Caveat - I am still learning, so apologies if this is off the mark of your original question. Hope this helps!
Resolved!
value_type is an object in std::map, and all it took for g++ to compile the code was to add this:
typedef typename map<const Key, Value>::value_type value_type;
Short version of my question:
When I tried to boost::bind io_service::post like this:
boost::bind(&boost::asio_io_service::post, &ios,
boost::bind(&MyClass::func, this, arg1, arg2));
I get errors like this:
error: no matching function for call to ‘bind(<unresolved overloaded function type>,
boost::asio::io_service*, boost::_bi::bind_t<void, boost::_mfi::mf2<void, MyClass,
const char*, const char*>, boost::_bi::list3<boost::_bi::value<MyClass*>,
boost::_bi::value<const char*>, boost::_bi::value<const char*> > >)’
How can I fix this?
Very simple test code: http://pastebin.com/V0uyLywC
Long version of my question:
I'm trying to write a generic event queue class, which you can add different types of events to the queue. You can subscribe to events by types, when that type of events is added, the subscribed callback function will be called.
An event queue object can potentially be subscribed by a different thread group from a different io_services. The internal queue of this class will be thread-safe using boost::lockfree:queue or boost::interprocess::message_queue (if this will be inter-process in the future). And the subscribed callback function will need to be called by its corresponding io_service's post, hence the attempted nested boost::bind above.
Is this a good and workable design?
Assuming this approach will work, I figured then an alternative would be also passing the io_service when you subscribe, but I was thinking 1) perhaps this class can be used when it does not involve io_services, and 2) this class shouldn't need to know about io_service.
Thanks all.
P.S. I have read boost::bind composition inside io_service::post function but it feels a bit different to my problem.
Update All solutions Live On Coliru
The problem
The first problem is that post has overloads, so you need to disambiguate. That's pretty ugly:
boost::bind(
static_cast<void (boost::asio::io_service::*)
(
boost::_bi::protected_bind_t<
boost::_bi::bind_t<
void,
boost::_mfi::mf2<void, MyClass, int, int>,
boost::_bi::list3<boost::_bi::value<MyClass *>,
boost::_bi::value<int>,
boost::_bi::value<int>
>
> > const&
)>(&boost::asio::io_service::post),
&ios_,
boost::protect(boost::bind(&MyClass::func, this, 7, 42)));
Of course, you could try to use decltype and some typedefs:
auto nested = boost::protect(boost::bind(&MyClass::func, this, 7, 42));
typedef decltype(nested) actual_t; // _bi::protected_bind_t<bind_t<void, mf2<void, MyClass, int, int>, list3<value<MyClass *>, value<int>, value<int> > > >
typedef void (boost::asio::io_service::*pmf)(actual_t const&);
boost::bind(static_cast<pmf>(&boost::asio::io_service::post), &ios_, nested);
But that would more or less refute the purpose of inline bind expressions in the first place.
Solution
Or you can use a helper functor, that hides the overload set behind a suitable polymorphic operator():
boost::bind(poster(ios_),
boost::protect(boost::bind(&MyClass::func, this, 7, 42)));
Where the poster helper looks like
struct poster {
typedef void result_type;
poster(boost::asio::io_service& ios) : ios_(ios) {}
boost::asio::io_service& ios_;
template<typename F> void operator()(F const& f) const {
ios_.post(f);
}
template<typename F> void operator()(F&& f) const {
ios_.post(std::move(f));
}
};
Surely what you are attempting to do is as simple as:
std::function<void()> f = [this, arg1, arg2]() {
ios_.post([this, arg1, arg2]() {
this->func(arg1, arg2);
});
};
now your thread can call f(), which will do the right thing...
Or am I missing something...
I have the following function defined:
template<class KEY, class VALUE, class HASH_FUNCTION,
class COMPARATOR_FUNCTION, class GREATER_THAN_FUNCTION>
bool Test3(size_t szCount, double dLoadFactor, vector<KEY>& vVals,
const HASH_FUNCTION& hf, const COMPARATOR_FUNCTION& cf,
const GREATER_THAN_FUNCTION& gf)
Then I call it in main().
int main()
{
vector<char*> vVals = GetWords("enwik8", 128*1024*1024);
SHash sh;
SHComp cf;
SHGreater gf;
Test3(1000, 0.7f, vVals, sh, cf, gf);
return 0;
}
And I get this error thrown at me:
/home/duminda/main.cpp:313: error: no matching function for call to
‘Test3(int, float, std::vector<char*, std::allocator<char*> >&, SHash&,
SHComp&, SHGreater&)’
I maybe missing something obvious. Any help would be appreciated. Thanks.
Looking at the function declaration, it has a template parameter V which isn't used anywhere in the actual parameter list. So it can't be deduced automatically at the call site.
Try just defining it as this instead:
template<class K class HF, class CF, class GF>
bool Test3(size_t szCount, double dLoadFactor, vector<K>& vVals, const HF& hf, const CF& cf, const GF& gf)
By the way, you might want to consider spending 5 seconds coming up with meaningful names. If V had had a sensible name, it might have been more obvious that it serves no purpose.
There is a template parameter VALUE that has not been resolved. It is never used.
Your function should already be able to derive this type if it is using it somewhere in the body. If it derives from a different template parameter, ensure you have a way of doing so. Possibly that template parameter has an internal typedef, for example if one of your comparison functions compares values of this type, they could have a value_type typedef.
Be certain to use typename in the body to get to this type if it is done that way.
Given the edited declaration
template<class KEY, class VALUE, class HASH_FUNCTION,
class COMPARATOR_FUNCTION, class GREATER_THAN_FUNCTION>
bool Test3(size_t szCount, double dLoadFactor, vector<KEY>& vVals,
const HASH_FUNCTION& hf, const COMPARATOR_FUNCTION& cf,
const GREATER_THAN_FUNCTION& gf);
and the comment: V is used by the function Test3. Is there a way for me to tell the compiler what the type of V is?
The problem with Test3(1000, 0.7f, vVals, sh, cf, gf); is that the compiler cannot deduce the template argument VALUE. But you can explicitly list template arguments to a function name like this:
Test3<const char*, value_type>(1000, 0.7f, vVals, sh, cf, gf);
Here the first two template arguments KEY=const char* and VALUE=value_type are given in < angle brackets >, and the rest can be deduced by the compiler.
If you change the order of KEY and VALUE in the template declaration, you could skip providing the KEY and let that be deduced:
template<class VALUE, class KEY, class HASH_FUNCTION,
class COMPARATOR_FUNCTION, class GREATER_THAN_FUNCTION>
bool Test3(size_t szCount, double dLoadFactor, vector<KEY>& vVals,
const HASH_FUNCTION& hf, const COMPARATOR_FUNCTION& cf,
const GREATER_THAN_FUNCTION& gf);
// ...
Test3<value_type>(1000, 0.7f, vVals, sh, cf, gf);