I want to use a tbb::concurrent_hash_map
with a key of std::tuple<A...>
where A...
will include boost unit types. The HashCompare struct I'm using at the moment looks like this:
template<typename K>
struct HashCompare {
static size_t hash( const K& key )
{
boost::hash<K> hasher;
return hasher(key);
}
static bool equal( const K& key1, const K& key2 ) {return key1 == key2;}
};
For all non boost unit types I tried this worked nicely but not so with boost units. I know that it is possible to extend the boost::hash
function with custom types but I seem unable to do that. As i have quite a lot of units I wanted to do this with a template of the following form:
std::size_t hash_value(T const& t){
boost::hash<double> hasher;
return hasher(t.value());
}
Putting this function in the boost
namespace or in the namespace where the units are defined didn't work.
How is it possible to extend the boost hashing function to custom types or write a template for the HashCompare::hash
function that takes only boost units?
Indeed Boost Units does not have hash support. You can add it:
template <typename... T>
size_t hash_value(boost::units::quantity<T...> const& q) {
using boost::hash_value; // enable ADL
return hash_value(q.value());
}
Smallest demo:
#include <boost/functional/hash.hpp>
#include <boost/units/unit.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/io.hpp>
#include <iostream>
using boost::hash_value;
template <typename... T>
size_t hash_value(boost::units::quantity<T...> const& q) {
using boost::hash_value; // enable ADL
return hash_value(q.value());
}
int main() {
using namespace boost::units::si;
auto l = 23.0*meter;
auto dt = 2.0*second;
std::cout << (l) << "\n";
std::cout << (dt) << "\n";
std::cout << (l/dt) << "\n";
std::cout << std::hex << std::showbase;
std::cout << hash_value(l) << "\n";
std::cout << hash_value(dt) << "\n";
std::cout << hash_value(l/dt) << "\n";
}
Prints
23 m
2 s
11.5 m s^-1
0x4037000000000000
0x4000000000000000
0x4027000000000000
boost::hash
in generic codeMake sure the overload is accessible on the point of instantiation. Enable argument dependent lookup (ADL):
#include <boost/units/unit.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/io.hpp>
#include <iostream>
#include <boost/functional/hash.hpp>
namespace boost::units {
template <typename... T>
size_t hash_value(quantity<T...> const& q) {
using boost::hash_value; // enable ADL
return hash_value(q.value());
}
}
namespace detail {
template<typename K>
struct HashCompare {
static size_t hash( const K& key )
{
boost::hash<K> hasher;
return hasher(key);
}
static bool equal( const K& key1, const K& key2 ) {return key1 == key2;}
};
template <typename T>
size_t test_mycompare(T const& v) {
return HashCompare<T>::hash(v);
}
}
int main() {
using namespace boost::units::si;
using boost::hash_value;
auto l = 23.0*meter;
auto dt = 2.0*second;
std::cout << (l) << "\n";
std::cout << (dt) << "\n";
std::cout << (l/dt) << "\n";
std::cout << std::hex << std::showbase;
std::cout << hash_value(l) << "\n";
std::cout << hash_value(dt) << "\n";
std::cout << hash_value(l/dt) << "\n";
std::cout << detail::test_mycompare(l) << "\n";
std::cout << detail::test_mycompare(dt) << "\n";
std::cout << detail::test_mycompare(l/dt) << "\n";
}
Prints
23 m
2 s
11.5 m s^-1
0x4037000000000000
0x4000000000000000
0x4027000000000000
0x4037000000000000
0x4000000000000000
0x4027000000000000