I'm declaring a map of string to a pair of pairs as follow:
std::map<std::wstring,
std::pair<std::pair<long, long>,
std::pair<long, long>>> reference;
And I initialize it as:
reference.insert(L"First",
std::pair<std::pair<long, long>,
std::pair<long, long>>(std::pair<long, long>(-1, -1),
std::pair<long, long>(0, 0)));
However, Visual C++ gives me the error "C2664, No constructor could take the source type, or constructor overload resolution was ambiguous".
I'm new to using templates and STL and I can't tell what I'm doing wrong.
The >>> can not be parsed correctly (unless you have a C++0x compiler).
Change to > > >
This:
reference.insert("First",
Should be:
reference.insert(L"First",
^^^
Also there is a utility function to make the construction of pairs easier:
std::pair<std::pair<long, long>, std::pair<long, long>>(std::pair<long, long>(-1, -1), std::pair<long, long>(0, 0))
Can be:
std::make_pair(std::make_pair(-1L,-1L),std::make_pair(0L,0L))
Try this:
reference[L"First"]
= std::make_pair(std::make_pair(-1L,-1L),std::make_pair(0L,0L));
C++ gets confused by the consecutive ">" when you close the template as it interprets that as the shift operator.
Add spaces between the closing templates, change >>> to > > >
map::insert itself takes a single std::pair argument, rather than two arguments. You can tidy up the code by using std::make_pair (which infers the template arguments from the function arguments), to get something like:
reference.insert(std::make_pair("First",
std::make_pair(std::make_pair(-1L,-1L),
std::make_pair(0L,0L))));
You could simplify your code by creating a helper function to create pairs of pairs, analog to the std::make_pair helper function that is available in the standard library. Also using the maps operator[] for insertion results in easier to read code:
template<typename T, typename U, typename V, typename W>
std::pair< std::pair<T,U>, std::pair<V,W> > make_pair_pair(T t, U u, V v, W w) {
// using std::make_pair instead of the constructor for better readability
return std::make_pair(std::make_pair(t, u), std::make_pair(v, w));
}
reference[L"First"] = make_pair_pair(1,2,3,4);
It helps to use typedefs when debugging this sort of thing.
// test1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <map>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::pair<long, long> ElementType;
typedef std::pair<ElementType, ElementType> ValueType;
typedef std::wstring KeyType;
std::map<KeyType, ValueType> reference;
KeyType key = L"First";
reference[key] = ValueType(ElementType(-1, -1), ElementType(0, 0));
return 0;
}
Related
This question already has answers here:
Why can't I compile an unordered_map with a pair as key?
(9 answers)
Closed 4 years ago.
#include <bits/stdc++.h>
std::unordered_map<std::pair<int,int>, int> mp;
int main()
{
mp[make_pair(1, 2)]++;
}
When using the [] operator, I get this
error: no match for ‘operator[]’ (operand types are ‘std::unordered_map<std::pair<int, int>, int>’ and ‘std::pair<int, int>’)
However, when doing the same with std::map, no error occurs. why?
How can I make it works with std::unorderd_m?
when doing the same with std::map, no error occurs. why? And how can I
make it works with std::unorderd_map ?
Because they are simply different.
std::unorderd_map the elements are placed according to the hash of its keys.
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;
whereas the std::map needs simply a comparison function in order to sort the keys.
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
The reason why your std::map<std::pair<int,int>, int> got compiled is, the operator< is defined for std::pair and std::map uses it to sort its keys, whereas the hash function for std::pair has not been defined and hence std::unorderd_map need one to keep elemets in its buckets. This you need to define.
For instance, you can define a custom hash function as follows:
#include <unordered_map>
#include <cstddef>
#include <functional>
struct CustomHash
{
template <typename T, typename U>
std::size_t operator()(const std::pair<T, U> &x) const
{
return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
}
};
int main()
{
std::unordered_map<std::pair<int,int>, int, CustomHash> mp;
mp[std::make_pair(1, 2)]++;
return 0;
}
PS: #include <bits/stdc++.h>is a bad coding practice. Why? see this .
However I tweek the following code, there seems to be a point I am missing. It will not compile. I have two maps int -> int. I want to produce a third int -> int map containing all the key-value pairs from the two originals. (VS2013) Anyone?
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/has_key.hpp>
typedef boost::mpl::map <
boost::mpl::pair < boost::mpl::int_<7>, boost::mpl::int_<59> >
>::type Original1;
typedef boost::mpl::map <
boost::mpl::pair < boost::mpl::int_<11>, boost::mpl::int_<61> >
>::type Original2;
typedef boost::mpl::copy <
Original1,
boost::mpl::back_inserter < Original2 >
>::type Merged;
BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));
int _tmain(int argc, _TCHAR* argv[])
{
const int i = boost::mpl::at<Merged, boost::mpl::int_<7> >::type::value;
return 0;
}
There are two problems with your code. The simple one is here:
BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));
Keys are types, 7 is not a type. You want to check for the key mpl::int_<7>.
The second is here:
typedef boost::mpl::copy <
Original1,
boost::mpl::back_inserter < Original2 > // <==
>::type Merged;
mpl::back_inserter is the metaprogramming equivalent of std::back_inserter, which creates an OutputIterator which outputs via push_back(). Similarly, back_inserter requires a "Back Extensible Sequence" because it uses mpl::push_back. mpl::map isn't a Back Extensible Sequence. If you look at its reference, there's no push_back, only insert. So you need to do that:
using Merged =
mpl::copy<
Original1,
mpl::inserter<Original2, mpl::insert<mpl::_1, mpl::_2>> // <==
>::type;
I don't quite understand what mpl::quote is doing, but it seems broken (er, actually, mpl::insert takes 3 arguments and mpl::quote3 doesn't allow for defaulting the last arguments). If you write:
template <template <class... > class F>
struct quote {
template <class... Args>
struct apply {
using type = typename F<Args...>::type;
};
};
then you could have just written:
mpl::inserter<Original2, quote<mpl::insert>>
I am trying to familiarise myself with boost::hana. As an exercise I want to create a function that will remove duplicates from a hana::tuple using a user-provided comparison function. The problem I am facing is related to using hana::type_c's for storing types as objects. Here is what I have
#include <boost/hana/equal.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/unpack.hpp>
#include <boost/hana/pair.hpp>
#include <boost/hana/any_of.hpp>
#include <boost/hana/second.hpp>
#include <boost/hana/fold.hpp>
#include <boost/hana/core/make.hpp>
#include <boost/hana/core/tag_of.hpp>
#include <iostream>
template <class>
struct what_is;
namespace hana = boost::hana;
// simply push back an element to the sequence
auto push_back = [](auto seq, auto t) {
using namespace boost::hana;
return unpack(seq, [&](auto&&... element){return make<typename tag_of<decltype(seq)>::type>(element..., t);});
};
// this is the main function
auto remove_duplicates = [](auto seq, auto comp) {
using namespace boost::hana;
auto f = [&](auto state, auto el){
return if_( any_of(state, partial(comp, el)),
[=](){return state;},
[=](){return push_back(state, el);})();
};
return fold(seq, make<typename tag_of<decltype(seq)>::type>(), f);
};
// user-defined comparison function
// elements are considered equal if only second element of pairs are equal
auto comp_pair = [](auto&& t1, auto&& t2) {
using namespace boost::hana;
return equal(second(t1), second(t2));
};
int main() {
auto my_tuple1 = hana::tuple_t<int, float, double, int, float>;
auto no_dups1 = remove_duplicates(my_tuple1, hana::equal); // this is fine, decltype(no_dups1) -> tuple< type<int>, type<float>, type<double> >
auto my_tuple2 = hana::tuple_t< hana::pair<int, int>, hana::pair<float, int>, hana::pair<float, float> >;
// auto no_dups2 = remove_duplicates(my_tuple2, comp_pair); // what I want here is tuple< type<pair<int, int>>, type<pair<float, float>> >
}
The last line creates problems as there is no second element to extract from a hana::type<pair<X,Y>>. For this to work I would have to create a very ugly sequence such as tuple< pair<type<int>, type<int>>, pair<type<double>, type<int>>, pair<type<float>, type<double>> >. As you can imagine this can grow bad really quickly, for instance if I had a sequence tuple<int, pair<X,Y>, double, float> etc. Is there any way I can create a uniform way to deal with this? I come from an MPL/fusion background and there I can work directly with the types without the need to wrap the types. Thank you
Unlike Fusion, Hana does not implicitly translate values to types. In general, this is nice because it means you get to use the more expressive value syntax. On the other hand, for some use cases where you really want to extract the wrapped types, you have to do it explicitly with Hana while Fusion does it for you under the hood.
I see two options for what you're trying to achieve. The first solution is to change your comp_pair function so that it unwraps the pairs itself:
template <typename T1, typename U1, typename T2, typename U2>
constexpr auto comp_pair(hana::basic_type<hana::pair<T1, U1>>,
hana::basic_type<hana::pair<T2, U2>>)
{
return hana::type_c<U1> == hana::type_c<U2>;
}
...
auto no_dups2 = remove_duplicates(my_tuple2, [](auto pair1, auto pair2) {
return comp_pair(pair1, pair2);
});
The second solution, which I find more idiomatic, is to actually hold your types as objects:
// This could arguably be part of Hana, just like we provide tuple_t
template <typename T, typename U>
constexpr auto pair_t = hana::make_pair(hana::type_c<T>, hana::type_c<U>);
auto tuple2 = hana::make_tuple(pair_t<int, int>, pair_t<double, int>, pair_t<float, double>);
auto nodups2 = remove_duplicates(tuple2, [](auto p1, auto p2) {
return hana::second(p1) == hana::second(p2);
});
However, you say:
As you can imagine this can grow bad really quickly, for instance if I had a sequence tuple<int, pair<X,Y>, double, float> etc. Is there any way I can create a uniform way to deal with this?
I'm not sure I follow here. Are you saying that you might want to have something like tuple<type<int>, pair<type<X>, type<Y>>, type<double>, type<float>>, and are looking for a generic way of achieving this? If so, then I must say I highly suspect there's a better way of achieving whatever you're trying to do. I can try to help if you provide more context.
Hope this helps!
I want to multiply each element in an mpl::vector by an int.
First, a metafunction to multiply an int_ with an int.
template <int i>
struct multiply_scalar
{
template<typename T> struct apply
{
typedef int_<(T::value * i)> type;
};
};
Here are the calls I want to make.
typedef vector<int_<3>, int_<4> > my_vec;
typedef typename transform< my_vec, multiply_scalar<2> >::type my_vec_2;
typedef vector<int_<6>, int_<8> > my_vec_3;
BOOST_MPL_ASSERT(( boost::is_same< my_vec_2, my_vec_3 > )); //Fails
//type of my_vec2 is: boost::mpl::v_item<mpl_::int_<8>, boost::mpl::v_item<mpl_::int_<6>, boost::mpl::vector0<mpl_::na>, 0>, 0>
Why isn't the resulting vector simply a vector<int_<6>, int_<8>>? Am I holding it wrong? Probably the metafunction or the transform is not applied in the right way.
Mainly because of some implementation issues in C++03, the writers of the MPL
had to use non-obvious techniques for representing sequences, one of which is
the usage of types like
boost::mpl::vector0<>
boost::mpl::vector1<T>
boost::mpl::vector2<T, U>
... etc
Instead of simply writing
boost::mpl::vector<>
boost::mpl::vector<T>
boost::mpl::vector<T, U>
as one would do with variadic templates in C++11 and beyond. Another technique
is to create some kind of reverse linked list when you insert stuff in a vector,
which is what you're looking at in your example:
boost::mpl::v_item<mpl_::int_<8>, // 2nd element
boost::mpl::v_item<mpl_::int_<6>, // 1st element
boost::mpl::vector0<mpl_::na>, 0>, 0> // empty list
Because of this, the documentation
for boost::mpl::transform does not specify exactly what is the type of boost::mpl::transform<s,op,in>::type.
Actually, it only guarantees that it's a type equivalent to
typedef lambda<op>::type f;
typedef lambda<in::operation>::type in_op;
typedef fold<
s
, in::state
, bind< in_op, _1, bind<f, _2> >
>::type r; // <-- the return type is equivalent to this r
This probably does not help you unless you already know the MPL well enough that
you don't ask questions on SO about it ;-), so basically it means that it returns
a new type that's like a boost::mpl::vector, except for its actual type which may
be anything like I showed above. In particular, this type is guaranteed to be a model
of the Forward Sequence concept.
When you use boost::is_same<T, U>, you're actually asking whether T and U
are precisely the same types. You should now see clearly why this is not what
you actually want. Instead, you want to do some kind of deep comparison of those
two sequences, which both represent vectors. To check whether two Forward
Sequences are equal, you must use the boost::mpl::equal
algorithm instead. The following will work:
#include <boost/mpl/assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
using namespace boost::mpl;
template <int i>
struct multiply_scalar
{
template<typename T> struct apply
{
typedef int_<(T::value * i)> type;
};
};
typedef vector<int_<3>, int_<4> > my_vec;
typedef transform< my_vec, multiply_scalar<2> >::type my_vec_2;
typedef vector<int_<6>, int_<8> > my_vec_3;
BOOST_MPL_ASSERT(( boost::mpl::equal< my_vec_2, my_vec_3 > ));
This question already has answers here:
C++ unordered_map using a custom class type as the key
(7 answers)
Closed 8 years ago.
I have to make an unordered_map consisting of the following keys and value:
key: unsigned char, unsigned char, unsigned char
value: structure(int,int)
Here is my code to define that:
namespace G {
typedef std::tuple< unsigned char, unsigned char , unsigned char> key_t;
struct IndexGuide
{
int index;
int SerialNo;
};
typedef std::unordered_map<const key_t,IndexGuide> GuideDouble;
}
using namespace G;
Is there anything wrong in this code because when I link these files on linux terminal. It gives me errors.Some part of the error as follows
In function `std::__detail::_Hash_code_base const, std::pair const, G::IndexGuide>,
std::_Select1st const, G::IndexGuide> >,
std::equal_to
const>, std::hash const>, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
false>::_M_bucket_index(std::__detail::_Hash_node const, G::IndexGuide>, false>
const*, unsigned int) const':
So your basic problem is that you don't have a hasher for std::tuple -- the standard library does not currently come with one by default. I think this is an oversight.
You cannot add a default hasher for std::tuple -- either for all tuples or for your particular list -- because the standard says you aren't allowed to:
17.6.4.2.1 Namespace std [namespace.std]/1 The behavior of a C++ program is undefined if it adds declarations or definitions to
namespace std or to a namespace within namespace std unless otherwise
specified. A program may add a template specialization for any
standard library template to namespace std only if the declaration
depends on a user-defined type and the specialization meets the
standard library requirements for the original template and is not
explicitly prohibited.
So this leaves you with either writing a custom hasher for your tuple type, and passing it to your unordered_map, or using a type that isn't merely std::tuple for your key, or writing a custom hasher that supports every tuple (including recursive tuples) while also supporting hash<T> lookup for non-tuples. A 4th option would be to write your own ADL-based hash system and set it up so that types with valid std::hash specializations use that, with various other fallbacks.
I will illustrate the 3rd option above.
First, you want to be able to combine two hash values in a way that doesn't lead to many spurious collisions.
inline std::size_t hash_result_combine(std::size_t lhs, std::size_t rhs)
{
return lhs ^( rhs + 0x9e3779b9 + (lhs<<6) + (lhs>>2));
}
this takes two hash outputs, and combines them. We can then chain this any number of times. (constants borrowed from https://stackoverflow.com/a/7111460/1774667 )
Next, some indexing boilerplate. Most generic work with std::tuple requires this stuff:
template<unsigned...>struct indexes{};
template<unsigned Max, unsigned... Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...> {};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
Finally, a hasher class that works with nearly every type:
struct my_hasher {
template<typename... Args>
std::size_t operator()(indexes<>, std::tuple<Args...> const& tup) const {
return 0;
}
template<unsigned I, unsigned... Is,typename... Args>
std::size_t operator()(indexes<I, Is...>,std::tuple<Args...> const& tup) const {
return hash_result_combine( (*this)(std::get<I>(tup)), (*this)(indexes<Is...>, tup) );
}
template<typename... Args>
std::size_t operator()(std::tuple<Args...> const& tup) const {
return (*this)(make_indexes<sizeof...(Args)>(), tup);
}
template<typename T>
std::size_t operator()(T const& t) const { return std::hash<T>()(t); }
};
you can pass my_hasher to an unordered_set in place of hash<T> for tuples, tuples containing tuples, or even for scalars -- it is very generous.
typedef std::unordered_map<const key_t,IndexGuide, my_hasher> GuideDouble;
and now we properly hash key_t.
You have to provide a hash function which tells std::unordered_map how to produce a hash value from your key_t. You can do it by specialization of hash template functor:
provide a Key:
struct Key{
unsigned char first;
unsigned char second;
unsigned char third;
bool operator==(const Key &other) const {
return (first == other.first
&& second == other.second
&& third == other.third);
}
};
specialize hash template:
namespace std {
template <>
struct hash< Key>
{
std::size_t operator()(const Key& k) const
{
using std::hash;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<char>()( k.first)
^ (hash<char>()( k.second) << 1)) >> 1)
^ (hash<int>()( k.third) << 1);
}
};
}
std::unordered_map< Key, IndexGuide> myMap;
As I said in comments, you can take a look at this SO thread.
unordered_set is implemented using a hash table.
in order to use unordered_set for a type that you defined you need to specialize the hash<> template for that type, as follows:
namespace std {
template <> struct hash<key_t>
{
size_t operator()(const key_t & t) const
{
// the logic for hashing
}
};
}
There is no default hasher for std::tuple.
You may use this code snippet Generic hash for tuples in unordered_map / unordered_set