If I have definitions like:
typedef map<string, Foo> Foo_map_1
typedef map<string, Foo_map_1> Foo_map_2
typedef map<string, Foo_map_2> Foo_map_3
typedef map<string, Foo_map_3> Foo_map_4
typedef map<string, Foo_map_4> Foo_map_5
Is there anyway I can generalize that so I could do, for example,
Foo_map<10>
and have a 10-fold nested map. I don't need something like boost::recursive_wrapper because the number of levels is always constant.
This is seems easy enough even for the limited C++ metaprogramming power:
#include <map>
#include <string>
template<int N, typename K, typename V>
struct NMap { typedef std::map<K, typename NMap<N-1, K, V>::type> type; };
template<typename K, typename V>
struct NMap<1, K, V> { typedef std::map<K, V> type; };
int main(int argc, const char *argv[]) {
NMap<3, int, std::string>::type m;
m[1][2][3] = "Test";
return 0;
}
This works for me.
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct Foo
{
Foo() : _in(0) {}
Foo(int in) : _in(in) {}
int _in;
};
template <int N> struct Foo_map
{
map<string, Foo_map<N-1> > foo_Map;
Foo_map<N-1>& operator[](string const& key) { return foo_Map[key]; }
};
template <> struct Foo_map<1>
{
map<string, Foo> foo_Map;
Foo& operator[](string const& key) { return foo_Map[key]; }
};
int main()
{
Foo_map<1> map1;
map1["abcd"] = Foo(10);
Foo_map<2> map2;
map2["a"]["b"] = Foo(20);
Foo_map<10> map10;
map10["a"]["b"]["c"]["d"]["e"]["f"]["g"]["h"]["i"]["j"] = Foo(100);
std::cout << map1["abcd"]._in << std::endl;
std::cout << map2["a"]["b"]._in << std::endl;
std::cout << map10["a"]["b"]["c"]["d"]["e"]["f"]["g"]["h"]["i"]["j"]._in << std::endl;
}
The output of running the program:
10
20
100
Related
For my unordered map I would like to use as keys pairs of (cpp_int, int) where cpp_int are boost multiprecision integers:
#include <boost/multiprecision/cpp_int.hpp>
#include <unordered_map>
using boost::multiprecision::cpp_int;
std::unordered_map<std::pair<cpp_int, int>, double> myMap
Searching on this site I have found many suggestions of using a custom hash function for std::pair<int,int> as keys, but I couldn't found how to deal with std::pair<cpp_int, int>.
Update: To clarify, I have tried a hash function I found on the web (for (int,int):
#include <boost/multiprecision/cpp_int.hpp>
#include <unordered_map>
using boost::multiprecision::cpp_int;
typedef std::pair<cpp_int, int> MyPair;
struct MyHash {
public:
size_t operator()(MyPair x) const throw() {
size_t h = x.first * 1 + x.second * 100000;
return h;
}
};
void function()
{
std::unordered_map<MyPair, double, MyHash> M;
}
This doesn't compile:
error: cannot convert ‘boost::enable_if_c<true, boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_add, boost::multiprecision::detail::expression<boost::multiprecision::detail::terminal, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<> >, void, void, void>, boost::multiprecision::detail::expression<boost::multiprecision::detail::terminal, int, void, void, void>, int, void> >::type {aka boost::multiprecision::detail::expression<boost::multiprecision::detail::multiply_add, boost::multiprecision::detail::expression<boost::multiprecision::detail::terminal, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<> >, void, void, void>, boost::multiprecision::detail::expression<boost::multiprecision::detail::terminal, int, void, void, void>, int, void>}’ to ‘size_t {aka long unsigned int}’ in initialization
size_t h = x.first * 1 + x.second * 100000;
^
My question is: how to use pairs of (cpp_int,int) as keys in an unordered_map?
Thank you very much in advance!
Update 2:
Thanks to #sehe for pointing me to his answer (in which he provided a hash function for cpp_int). Combining with this answer (which shows how to combine two hash functions for a pair), I've come up with the following solution (it compiles fine, I'll need to test on my problem to see if it works):
#include <boost/archive/binary_oarchive.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_int/serialize.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/functional/hash.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <unordered_map>
using boost::multiprecision::cpp_int;
typedef std::pair<cpp_int, int> MyPair;
namespace mp_hashing {
namespace io = boost::iostreams;
struct hash_sink {
hash_sink(size_t& seed_ref) : _ptr(&seed_ref) {}
typedef char char_type;
typedef io::sink_tag category;
std::streamsize write(const char* s, std::streamsize n) {
boost::hash_combine(*_ptr, boost::hash_range(s, s+n));
return n;
}
private:
size_t* _ptr;
};
template <typename T> struct hash_impl {
size_t operator()(T const& v) const {
using namespace boost;
size_t seed = 0;
{
iostreams::stream<hash_sink> os(seed);
archive::binary_oarchive oa(os, archive::no_header | archive::no_codecvt);
oa << v;
}
return seed;
}
};
}
namespace std {
template <typename backend>
struct hash<boost::multiprecision::number<backend> >
: mp_hashing::hash_impl<boost::multiprecision::number<backend> >
{};
}
struct pair_hash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1,T2> &p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
// Mainly for demonstration purposes, i.e. works but is overly simple
// In the real world, use sth. like boost.hash_combine
return h1 ^ h2;
}
};
void function()
{
std::unordered_map<MyPair, double, pair_hash> M;
}
Yes, you took the Multiprecision hash I contributed earlier and added the hash for std::pair. I'm not a fan of handrolling the hash combination (good general hash combination is not trivial).
So I'd do the same with boost::hash_combine:
template <typename K, typename V>
struct hash<std::pair<K, V> >
{
size_t operator()(std::pair<K, V> const& pair) const {
size_t seed = std::hash<K>{}(pair.first);
boost::hash_combine(seed, pair.second);
return seed;
}
};
Live On MSVC RexTester
#include <iostream>
#include <iomanip>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_int/serialize.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/functional/hash.hpp>
namespace mp_hashing {
namespace io = boost::iostreams;
struct hash_sink {
hash_sink(size_t& seed_ref) : _ptr(&seed_ref) {}
typedef char char_type;
typedef io::sink_tag category;
std::streamsize write(const char* s, std::streamsize n) {
boost::hash_combine(*_ptr, boost::hash_range(s, s+n));
return n;
}
private:
size_t* _ptr;
};
template <typename T> struct hash_impl {
size_t operator()(T const& v) const {
using namespace boost;
size_t seed = 0;
{
iostreams::stream<hash_sink> os(seed);
archive::binary_oarchive oa(os, archive::no_header | archive::no_codecvt);
oa << v;
}
return seed;
}
};
}
#include <unordered_map>
#include <boost/unordered_map.hpp>
namespace std {
template <typename backend>
struct hash<boost::multiprecision::number<backend> >
: mp_hashing::hash_impl<boost::multiprecision::number<backend> >
{};
template <typename K, typename V>
struct hash<std::pair<K, V> >
{
size_t operator()(std::pair<K, V> const& pair) const {
size_t seed = std::hash<K>{}(pair.first);
boost::hash_combine(seed, pair.second);
return seed;
}
};
}
int main() {
using boost::multiprecision::cpp_int;
std::unordered_map<std::pair<cpp_int, int>, int> m {
{ { cpp_int(1) << 111, -1 }, 1 },
{ { cpp_int(2) << 222, -2 }, 2 },
{ { cpp_int(3) << 333, -3 }, 3 },
};
for (auto& p : m)
std::cout << p.first.first << " -> " << p.second << "\n";
}
Here, I tried to make a map that its vertex can be user-defined class. But when I try to add template type element to the unordered_set it gives error. The code is:
#include <iostream>
#include <unordered_set>
#include <string>
#include <vector>
#include <functional>
template<class T> class Edge;
template<class T> class Vertex{ // Made it a class just for its constructor.
public:
template<class A> Vertex(A vert){
A vertex = vert;
std::unordered_set<Edge<A>> adjlist;
}
};
template<class T> class Edge{ // Made it a class just for its constructor.
public:
template<class A> Edge(Vertex<A> vert1, Vertex<A> vert2, int w){
Vertex<A> *origin = &vert1;
Vertex<A> *target = &vert2;
}
};
template<class T>
class WUG{
private:
std::unordered_set<Vertex<T>> vertices;
std::unordered_set<Edge<T>> edges;
int num_of_edges;
int num_of_vertices;
public:
WUG() {
num_of_edges = 0;
num_of_vertices = 0;
}
void addVertex(T newVert) {
Vertex<T> temp = Vertex<T>(newVert);
vertices.emplace(temp); //Problem is here
}
int main(int argc, char** argv) {
WUG<char> g1 = WUG<char>();
g1.addVertex('A');
g1.addVertex('B');
g1.addVertex('C');
return 0;
}
Error: it opens hashtable_policy.h and gives error at
template <typename _Key, typename _Hash>
struct __is_noexcept_hash : std::integral_constant<bool,
noexcept(declval<const _Hash&>()(declval<const _Key&>()))> //Here
{ };
[Error] no match for call to '(const std::hash<Vertex<char> >) (const Vertex<char>&)'
How do you emplace a template type object to unordered_set? How about pair of 2 template?
I believe you need to provide special hashing and comparison functions to make the hash set (or in my example's case, hash map) work. Here is a minimal example. Tested with C++11.
#include <unordered_map>
#include <iostream>
#include <algorithm>
template<typename T>
struct foo {
typedef T value_type;
foo(T x) : x(x) {}
T x;
};
template<typename T>
struct foo_hasher {
int operator()(const T &val) const {
return std::hash<typename T::value_type>()(val.x);
}
};
template<typename T>
struct foo_equality {
bool operator()(const T &left, const T& right) const {
return left.x == right.x;
}
};
int main() {
typedef std::unordered_map<foo<int>, int, foo_hasher<foo<int>>, foo_equality<foo<int>>> Map;
Map mp;
foo<int> x(5);
mp[x] = 10;
mp[foo<int>(10)] = 22;
std::for_each(mp.begin(), mp.end(), [](const Map::value_type &val) {
std::cout << val.first.x << ", " << val.second << "\n";
});
}
Note that both my hashing and equality function are not at all restrictive - they are wrt T rather than foo, but the principal should be the same.
I have a map where the value is a weak pointer. This works:
While I can write this:
for_each( IFoo::foo_wptr obj, objects | range::map_values ) {
IFoo::foo_ptr myObj = obj.lock();
if( myObj ) myObj->notify();
}
I'd much rather have a new range that transforms to a locked shared pointer. Something like this:
for_each( IFoo::foo_ptr obj, objects | range::map_values | range::locked ) {
if( obj ) obj->notify();
}
however, I've been unable to figure out what that transform should look like; or if it should even be a transform.
Does anyone have an idea? I'm convinced this pattern may quite common.
Here's an example that I literally just threw together:
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/foreach.hpp>
#include <map>
#include <vector>
struct weak_ptr_locker
{
template <typename Sig>
struct result;
template <typename F, typename T>
struct result<F(boost::weak_ptr<T>&)>
{
typedef boost::shared_ptr<T> type;
};
template <typename T>
boost::shared_ptr<T> operator()(const boost::weak_ptr<T>& pWeak) const
{
return pWeak.lock();
}
};
template<typename R>
struct lock_transform_range :
boost::iterator_range< boost::transform_iterator< weak_ptr_locker, typename boost::range_iterator<R>::type> >
{
private:
typedef boost::iterator_range< boost::transform_iterator< weak_ptr_locker, typename boost::range_iterator<R>::type> > base;
public:
typedef boost::transform_iterator< weak_ptr_locker, typename boost::range_iterator<R>::type > iterator;
lock_transform_range(R& r)
: base(iterator(boost::begin(r)), iterator(boost::end(r)))
{}
};
namespace detail
{
struct lock_transform_forwarder {};
}
template< class BidirectionalRng >
inline lock_transform_range<BidirectionalRng> operator | (BidirectionalRng& r, detail::lock_transform_forwarder)
{
return lock_transform_range<BidirectionalRng>(r);
}
template< class BidirectionalRng >
inline lock_transform_range<const BidirectionalRng> operator | (const BidirectionalRng& r, detail::lock_transform_forwarder)
{
return lock_transform_range<const BidirectionalRng>(r);
}
namespace
{
const detail::lock_transform_forwarder locked = detail::lock_transform_forwarder();
}
struct Foo
{
Foo(int i)
: i(i)
{}
int i;
void notify()
{
std::cout << i << std::endl;
}
};
int main(int argc, char* argv[])
{
typedef std::map<int, boost::weak_ptr<Foo> > Map;
typedef boost::shared_ptr<Foo> FooPtr;
Map objects;
std::vector<FooPtr> storage;
for (int i = 0; i < 10; ++i)
{
storage.push_back(boost::make_shared<Foo>(i));
objects[i] = storage.back();
}
using namespace boost::adaptors;
for_each(FooPtr obj, objects | map_values | locked)
{
if (obj)
obj->notify();
}
return 0;
}
How might I implement the function below to convert from vector of Value to a Container? I wish to assert if not all the members of values are of the same type, i.e. if the vector contains a mix of strings and ints. This is because the function's return value is either a std::vector<int> or a std::vector<std::string>.
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
Container valuesToContainer(const std::vector<Value>& values)
{
return Container();
}
struct converter_visitor : public boost::static_visitor<Container>
{
const std::vector<Value> & _cont;
converter_visitor(const std::vector<Value> &r) : _cont(r) {}
template<class T>
Container operator()(const T &) const {
std::vector<T> ans;
ans.reserve(_cont.size());
for (int i=0;i < _cont.size();++i)
ans.push_back( boost::get<T>(_cont[i]));
return ans;
}
};
Container valuesToContainer(const std::vector<Value> & values) {
//assuming !values.empty()
return boost::apply_visitor( converter_visitor(values),values.front());
}
This will throw a bad_get if not all the elements of values are of the same type.
This could come in handy, maybe:
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values);
The difference with the function requested by the OP is that instead of 'erroring' when not all element types agree, it will return a tuple of vectors ("VectorPack"), and you can simply select which is the one you want.
Demo program:
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <tuple>
#include <vector>
using std::get;
template <typename... T> using VariantVector = std::vector<boost::variant<T...>>;
template <typename... T> using VectorPack = std::tuple<std::vector<T>...>;
namespace detail
{
template <typename T>
struct VectorSplitterMixin {
void operator()(T const& v) { _bucket.push_back(v); }
std::vector<T> _bucket;
};
template <typename... T>
struct VectorSplitter : boost::static_visitor<>, VectorSplitterMixin<T>...
{
typedef VectorPack<T...> product_t;
product_t product() {
return product_t { std::move(static_cast<VectorSplitterMixin<T>*>(this)->_bucket)... };
}
};
}
template <typename T> struct X;
template <typename... T>
VectorPack<T...> splitVectors(VariantVector<T...> const &values)
{
auto splitter = detail::VectorSplitter<T...>();
for (auto& val : values)
boost::apply_visitor(splitter, val);
return splitter.product();
}
int main()
{
typedef boost::variant<int, std::string> Value;
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
const std::vector<Value> vec { 42, "hello world", 1, -99, "more" };
auto vectorPack = splitVectors<int, std::string>(vec);
for (auto i : get<0>(vectorPack))
std::cout << "int:" << i << ", ";
std::cout << "\n";
for (auto& s : get<1>(vectorPack))
std::cout << "string:" << s << ", ";
std::cout << "\n";
}
Printing:
int:42, int:1, int:-99,
string:hello world, string:more,
I am struggling with a small piece of functionality I'm looking for.
I have a class which contains a fusion::map. I would like to use a variadic constructor to initialise the elements in that map.
I expect the easiest way to do this is to construct a fusion::vector from the constructor arguments, and then call for_each on the map, and setting each pair's value to its corresponding element in the vector.
However, in order to do this I need to calculate the index of the pair, based on its key type. (pair::first_type)
Can anyone help me?
Please see example code below:
#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/has_key.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/mpl/transform.hpp>
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
// given a field, returns a fusion pair of <field, field::type>
template<class field>
struct make_pair
{
typedef typename fusion::result_of::make_pair<field, typename field::type>::type type;
};
// given a sequence of fields, returns a fusion map which maps field -> field::type
template<class... fields>
struct make_map
{
typedef typename boost::fusion::vector<fields...> vector;
typedef typename mpl::transform<vector, make_pair<mpl::_1>>::type pair_sequence;
typedef typename fusion::result_of::as_map<pair_sequence>::type type;
};
// initialise each member of a map with the corresponding element in the vector
template<typename vector>
struct init
{
init(vector& v) : _v(v) {}
template <typename pair>
void operator()(pair const& data) const
{
// TODO: use pair::first_type to find the index of this pair in the map, and set
// data.second to at_c<index>(_v);
}
vector& _v;
};
struct field1 { typedef int type; };
struct field2 { typedef int type; };
struct my_map
{
template<typename... args>
my_map(args... a)
{
typedef typename boost::fusion::vector<args...> vector;
vector arg_vec(a...);
fusion::for_each(_map, init<vector>(arg_vec));
}
typedef typename make_map<field1, field2>::type map;
map _map;
};
struct print
{
template <typename pair>
void operator()(pair const& data) const
{
std::cout << data.second << " ";
}
};
int main()
{
my_map m(1, 2);
fusion::for_each(m._map, print()); // should print '1 2'
return 0;
}
Answering my own question:
fusion::copy is all I needed:
fusion::copy(arg_vec, _map);
Adding another answer to my own question, this time for the use-case where the number of arguments is less than or equal to the number of elements in the map.
A working solution is below:
#include <iostream>
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/fusion/include/has_key.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/fusion/include/copy.hpp>
#include <boost/fusion/include/begin.hpp>
#include <boost/fusion/include/next.hpp>
#include <boost/fusion/include/key_of.hpp>
#include <boost/fusion/iterator/key_of.hpp>
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
// given a field, returns a fusion pair of <field, field::type>
template<class field>
struct make_pair
{
typedef typename fusion::result_of::make_pair<field, typename field::type>::type type;
};
// given a sequence of fields, returns a fusion map which maps field -> field::type
template<class... fields>
struct make_map
{
typedef typename fusion::result_of::as_map<typename mpl::transform<boost::fusion::vector<fields...>, make_pair<mpl::_1>>::type>::type type;
};
//-------------------------------------------------------------------------------------------
// iterate through a fusion map to find the index of a given key
template<typename iter, typename key_type, typename seek_type>
struct key_index
{
typedef typename fusion::result_of::next<iter>::type next_iter;
typedef typename fusion::result_of::key_of<next_iter>::type next_key;
enum { value = 1 + key_index<next_iter, next_key, seek_type>::value };
};
template<typename iter, typename seek_type>
struct key_index<iter, seek_type, seek_type>
{
enum { value = 0 };
};
//-------------------------------------------------------------------------------------------
// copy an element from a vector to a map, if the index in the vector exists
template<typename map, typename vector, int index, bool in_vec>
struct do_copy
{
template<typename T>
void operator()(const vector& v, const T& dest)
{
const_cast<T&>(dest) = fusion::at_c<index>(v);
}
};
template<typename map, typename vector, int index>
struct do_copy<map, vector, index, false>
{
template<typename T>
void operator()(const vector&, const T&)
{ }
};
//-------------------------------------------------------------------------------------------
// initialise a map with the corresponding elements in a vector, vector may be smaller than the map
template<typename vector, typename map>
struct init
{
init(const vector& v) : _v(v) {}
template <typename pair> void operator()(const pair& data) const
{
typedef typename fusion::result_of::begin<map>::type begin_iter;
typedef typename fusion::result_of::key_of<begin_iter>::type key_type;
enum { index = key_index<begin_iter, key_type, typename pair::first_type>::value };
enum { in_vec = fusion::result_of::size<vector>::type::value > index };
do_copy<map, vector, index, in_vec>()(_v, data.second);
}
private:
const vector& _v;
};
//-------------------------------------------------------------------------------------------
struct field1 { typedef std::string type; };
struct field2 { typedef int type; };
struct field3 { typedef double type; };
struct field4 { typedef std::string type; };
struct field5 { typedef int type; };
struct field6 { typedef double type; };
struct my_map
{
template<typename... args>
my_map(args... a)
{
typedef typename fusion::vector<args...> vector;
fusion::for_each(_map, init<vector, map>(vector(a...)));
}
typedef typename make_map<field1, field2, field3, field4, field5, field6>::type map;
map _map;
};
struct print
{
template <typename pair>
void operator()(pair const& data) const
{
std::cout << data.second << " ";
}
};
//-------------------------------------------------------------------------------------------
int main()
{
my_map m("hello world", 5, 2.4);
fusion::for_each(m._map, print());
std::cout << std::endl;
return 0;
}