C++ boost shared_ptr as a hash_map key
-
23-08-2019 - |
Question
I'm making a neural network and wanted to use a hash_map to keep weight references for output neurons for each neuron:
class Neuron; //forward declaration was there (sorry I forgot to show it earlier)
typedef double WEIGHT;
typedef stdext::hash_map<boost::shared_ptr<Neuron>,WEIGHT> NeuronWeightMap;
class Neuron
{
private:
NeuronWeightMap m_outputs;
//...
public:
Neuron();
~Neuron();
//...
WEIGHT GetWeight(const boost::shared_ptr<Neuron>& neuron) const
{
NeuronWeightMap::const_iterator itr = m_outputs.find(neuron);
if( itr != m_outputs.end() )
{
return itr->second;
}
return 0.0f;
}
};
I realize that I can't use the boost::shared_ptr as the key of a stdext::hash_map, so what would be another suggestion? Are there any work-arounds or is the only option to use a different key or maybe switch to an std::map? Thanks!
Here is the errors:
1>c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(61) : error C2440: 'type cast' : cannot convert from 'const boost::shared_ptr<T>' to 'size_t'
1> with
1> [
1> T=Neuron
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(99) : see reference to function template instantiation 'size_t stdext::hash_value<_Kty>(const _Kty &)' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(98) : while compiling class template member function 'size_t stdext::hash_compare<_Kty,_Pr>::operator ()(const _Kty &) const'
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Pr=std::less<boost::shared_ptr<Neuron>>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\hash_map(80) : see reference to class template instantiation 'stdext::hash_compare<_Kty,_Pr>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Pr=std::less<boost::shared_ptr<Neuron>>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(119) : see reference to class template instantiation 'stdext::_Hmap_traits<_Kty,_Ty,_Tr,_Alloc,_Mfl>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Ty=common_ns::WEIGHT,
1> _Tr=stdext::hash_compare<boost::shared_ptr<Neuron>,std::less<boost::shared_ptr<Neuron>>>,
1> _Alloc=std::allocator<std::pair<const boost::shared_ptr<Neuron>,common_ns::WEIGHT>>,
1> _Mfl=false
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\hash_map(90) : see reference to class template instantiation 'stdext::_Hash<_Traits>' being compiled
1> with
1> [
1> _Traits=stdext::_Hmap_traits<boost::shared_ptr<Neuron>,common_ns::WEIGHT,stdext::hash_compare<boost::shared_ptr<Neuron>,std::less<boost::shared_ptr<Neuron>>>,std::allocator<std::pair<const boost::shared_ptr<Neuron>,common_ns::WEIGHT>>,false>
1> ]
1> FILE_PATH_REMOVED\neuralnet.h(21) : see reference to class template instantiation 'stdext::hash_map<_Kty,_Ty>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Ty=common_ns::WEIGHT
1> ]
1>NeuralNet.cpp
1>c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(61) : error C2440: 'type cast' : cannot convert from 'const boost::shared_ptr<T>' to 'size_t'
1> with
1> [
1> T=Neuron
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(99) : see reference to function template instantiation 'size_t stdext::hash_value<_Kty>(const _Kty &)' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(98) : while compiling class template member function 'size_t stdext::hash_compare<_Kty,_Pr>::operator ()(const _Kty &) const'
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Pr=std::less<boost::shared_ptr<Neuron>>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\hash_map(80) : see reference to class template instantiation 'stdext::hash_compare<_Kty,_Pr>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Pr=std::less<boost::shared_ptr<Neuron>>
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\xhash(119) : see reference to class template instantiation 'stdext::_Hmap_traits<_Kty,_Ty,_Tr,_Alloc,_Mfl>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Ty=common_ns::WEIGHT,
1> _Tr=stdext::hash_compare<boost::shared_ptr<Neuron>,std::less<boost::shared_ptr<Neuron>>>,
1> _Alloc=std::allocator<std::pair<const boost::shared_ptr<Neuron>,common_ns::WEIGHT>>,
1> _Mfl=false
1> ]
1> c:\program files (x86)\microsoft visual studio 8\vc\include\hash_map(90) : see reference to class template instantiation 'stdext::_Hash<_Traits>' being compiled
1> with
1> [
1> _Traits=stdext::_Hmap_traits<boost::shared_ptr<Neuron>,common_ns::WEIGHT,stdext::hash_compare<boost::shared_ptr<Neuron>,std::less<boost::shared_ptr<Neuron>>>,std::allocator<std::pair<const boost::shared_ptr<Neuron>,common_ns::WEIGHT>>,false>
1> ]
1> FILE_PATH_REMOVED\neuralnet.h(21) : see reference to class template instantiation 'stdext::hash_map<_Kty,_Ty>' being compiled
1> with
1> [
1> _Kty=boost::shared_ptr<Neuron>,
1> _Ty=common_ns::WEIGHT
1> ]
1>Generating Code...
Solution
You probably have Neuron
declared in your .h file.
So the below could work:
struct hasher {
size_t operator()(const boost::shared_ptr<Neuron>& n) { return (size_t)n.get(); }
};
typedef stdext::hash_map<boost::shared_ptr<Neuron>,WEIGHT,hasher> NeuronWeightMap;
The problem probably is that boost:shared_ptr
has no default hashing function (what one would look like?), so you just need to provide one.
OTHER TIPS
You could also provide a template specialization for the hash:
#include <functional>
#include <boost/shared_ptr.hpp>
template<class T>
class std::tr1::hash<boost::shared_ptr<T>> {
public:
size_t operator()(const boost::shared_ptr<T>& key) const {
return (size_t)key.get();
}
};
Works perfectly with unordered_set:
class Foo;
typedef boost::shared_ptr<Foo> FooPtr;
typedef std::tr1::unordered_set<FooPtr> FooSet;
A "normal" Neuron*
should work as key for the hash_map
:
typedef stdext::hash_map<Neuron*, WEIGHT> NeuronWeightMap;
If you want to lookup shared_ptr
-Neurons you can use shared_ptr
s get()
method to access the raw pointer:
NeuronWeightMap weights;
boost::shared_ptr<Neuron> n;
weights.find(n.get());
Since you already use Boost, why not use boost::unordered_map
for the hash table? It compiles out of the box with shared_ptr
for the key, though you better check how to do it properly (Boost.Unordered)
From the code above what is the compiler error?
Have you tried forward declaring the class Neuron?
class Neuron; // class Neuron must be forward declared to be used
typedef double WEIGHT;
typedef stdext::hash_map<boost::shared_ptr<Neuron>,WEIGHT> NeuronWeightMap;
class Neuron
{
private:
NeuronWeightMap m_outputs;
//...
public:
Neuron();
~Neuron();
//...
};
a standard map should also be fine in this case, what is your specific reason to use hash_map?
I find by adding a hash_value() function I can use a shared_ptr as a key in a stdext::hash_map. Below I compare using boost::unordered_map with std::hash_map
#include <boost/smart_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <hash_map>
#include <assert.h>
struct MyItem
{
int i;
};
typedef boost::shared_ptr<const MyItem> MyItem_csptr;
struct MyExtra
{
double d;
};
//Boost's unordered_map already knows how to hash shared_ptr
typedef boost::unordered_map<MyItem_csptr,MyExtra> MapMyItemToExtra;
//But for stdext::hash_map, we need to write this:
template<class T>
size_t hash_value(const boost::shared_ptr<T>& aSptr)
{
return reinterpret_cast<size_t>( aSptr.get() );
};
typedef stdext::hash_map<MyItem_csptr,MyExtra> MapMyItemToExtra2;
template<class MAP>
void TryMapMyItemToExtra_T()
{
MAP tMap;
MyItem_csptr tItem1(new MyItem);
MyItem_csptr tItem2(new MyItem);
tMap[tItem1].d=1.0;
tMap[tItem1].d=1.1;
tMap[tItem2].d=2.0;
assert( tMap[tItem1].d == 1.1 );
assert( tMap[tItem2].d == 2.0 );
}
void TryMapMyItemToExtra()
{
TryMapMyItemToExtra_T<MapMyItemToExtra>();
TryMapMyItemToExtra_T<MapMyItemToExtra2>();
}
Issue with hash function arises for stdext::hash_set
as well. Solution with declaring hash_value()
is the best since you can declare it just once in main headers file.