This is my first time working with pairs, totally confused.
How to initialize a pair as to insert it in the map?
Should I include some standard library for this?
#include <string>
#include <map>
using namespace std;
class Roads
{
public:
map< pair<string,string>, int > Road_map;
void AddRoad( string s, string d )
{ int b = 2 ; Road_map.insert( pair<s,d>, b) ; } //pair<s,d> is wrong here.
};
You can use std::make_pair:
Road_map[make_pair(s, d)] = b;
Alternatively, you can construct an std::pair like so:
Road_map[pair<string,string>(s,d)] = b;
The std::make_pair approach saves you having to name the types of s and d.
Notice that the appropriate function here is operator[] and not insert. std::map::insert takes a single argument which is a std::pair containing the key and value you want to insert. You would have to do that like this:
Road_map.insert(pair<const pair<string,string>, int>(make_pair(s, d), b);
You can make this a bit prettier with typedef:
typedef map<pair<string,string>, int> map_type;
Road_map.insert(map_type::value_type(map_type::key_type(s, d), b));
Use std::make_pair instead. Like so:
#include <string>
using namespace std;
class Roads
{
public:
map< pair<string,string>, int > Road_map;
void AddRoad( string s, string d )
{
int b = 2 ;
Road_map[make_pair(s,d)] = b;
}
};
For a map<K, T>, the value_type is actually pair<K const, T>. However, the easiest way to access this is by using typedefs:
typedef std::pair<std::string, std::string> string_pair;
typedef std::map<string_pair, int> map_type;
// ...
Road_map.insert(map_type::value_type(map_type::key_type(s, d), b));
In C++11 you can use the easier emplace interface:
Road_map.emplace(map_type::key_type(s, d), b);
Related
The vector constructor calls in the statement below construct vectors with 50 elements of identical values in each vector as values in the sviMap. The statement repeats vector<int> three times. Is there a more concise way to achieve this overall initialization of the sviMap where vector<int> appears only once in the statement?
map<string, vector<int>> sviMap { {"Leo", vector<int>(50, 101)} , {"Brad", vector<int>(50, 201)} };
Strictly speaking, no. You need to have template specialization and two instances of the vector.
But if you need to have "this text once", this workaround could work for you:
using vi = vector<int>;
map<string, vi> sviMap{ {"Leo", vi(50, 101)} , {"Brad", vi(50, 201)} };
Formally, this is not "the statement", but two statements, but the vector appears only once. If your goal is to have one point for changes, this could work.
I wanted to correct my mistake, so here's another solution.
And this one will result in vectors of the correct length.
I just used inheritance to create a vector type with a constructor that has the desired behavior, so you can then use initializer lists without extra specifics
#include <cassert>
#include <map>
#include <vector>
#include <string>
template<typename type_t>
class my_vector :
public std::vector<type_t>
{
public:
my_vector() = default;
my_vector(const size_t size, const type_t value) :
std::vector<type_t>(size, value)
{
}
};
int main()
{
std::map<std::string, my_vector<int>> sviMap{ { "Leo", {50, 101}}, { "Brad", {50, 201}} };
auto vec = sviMap["Leo"];
auto value = vec[23];
}
You can do it like this, just use nested initializers
#include <map>
#include <vector>
#include <string>
int main()
{
std::map<std::string, std::vector<int>> sviMap
{
{"Leo", {50, 101}},
{"Brad", {50, 201}}
};
auto vec = sviMap["Leo"];
}
I have a map defined and used like this
// def.h
struct X{};
struct Y{};
struct myStruct
{
X x;
Y y;
};
typedef std::unordered_map<std::pair<std::string, std::string>, myStruct> myMap;
namespace std
{
template<> struct pair<std::string, std::string>
{
std::string s1,s2;
pair(const std::string& a, const std::string& b):s1(a),s2(b){}
bool operator < (const pair<std::string,std::string>& r)
{
return (0 < r.s1.compare(s1) && (0 < r.s2.compare(s2)));
}
};
}
//use.cpp
class CUse
{
myMap m;
public:
CUse():m(0){}
};
Some errors emitted by the compiler are extracted as below
At the constructor CUse initialization,
note: see reference to function template instantiation
'std::unordered_map,myStruct,std::hash<_Kty>,std::equal_to<_Kty>,std::allocator>>::unordered_map(unsigned __int64)' being compiled
At the declaration of m in CUse
note: see reference to class template instantiation
'std::unordered_map,myStruct,std::hash<_Kty>,std::equal_to<_Kty>,std::allocator>>' being compiled
As #Bo Persson and #Sean Cline mentioned in the comments, you will need to use a custom hash function/functor to do that.
LIVE DEMO
#include <unordered_map>
#include <string>
#include <tuple>
#include <functional>
#include <cstddef>
#include <iostream>
struct myStruct { int x, y; };
using Key = std::pair<std::string, std::string>;
namespace something
{
struct Compare //custom hash function/functor
{
std::size_t operator()(const Key& string_pair) const
{
// just to demonstrate the comparison.
return std::hash<std::string>{}(string_pair.first) ^
std::hash<std::string>{}(string_pair.second);
}
};
}
using myMap = std::unordered_map<Key, myStruct, something::Compare>;
int main()
{
myMap mp =
{
{ { "name1", "name2" },{ 3,4 } },
{ { "aame1", "name2" },{ 8,4 } },
{ std::make_pair("fame1", "name2"),{ 2,4 } }, // or make pair
{ std::make_pair("fame1", "bame2"),{ 1,2 } }
};
for(const auto& it: mp)
{
std::cout << it.first.first << " " << it.first.second << " "
<< it.second.x << " " << it.second.y << std::endl;
}
return 0;
}
However, every symmetric pair will make almost same hashes and that can cause,
hash collisions and thereby less performance. Nevertheless, additional specializations for std::pair to compose hashes are available in boost.hash
An alternative solution, could be using std::map<>. There you can also specify the custom function/functor for the std::pair, in order to achieve the same map structure. Even though there you will not have to face hash-collisions, that would be well sorted which you might not want.
LIVE DEMO
#include <map>
#include <string>
#include <tuple>
#include <iostream>
struct myStruct { int x, y; };
using Key = std::pair<std::string, std::string>;
namespace something
{
struct Compare
{
bool operator()(const Key& lhs, const Key& rhs) const
{
// do the required comparison here
return std::tie(lhs.first, lhs.second) < std::tie(rhs.first, rhs.second);
}
};
}
using myMap = std::map<Key, myStruct, something::Compare>;
could you tell me why it is not good to use my data type in std ? My
type is defined in my own program anyway.
You shouldn't make it under the namespace of std, because it can cause a UB. A well defined situations/exceptions where you can extend std namespace are given here: https://en.cppreference.com/w/cpp/language/extending_std
Answer to the secondary question:
Thank you but could you tell me why it is not good to use my data type in std ? My type is defined in my own program anyway
You feel that you can define whatever you want in your program, right? (That is the impression you gave, at least.) Well, C++ implementations feel the same way about namespace std -- it is their namespace and they can define whatever they want in it (subject to the C++ standard, of course).
If an implementation needs to define a (possibly undocumented) helper function/class/whatever, the expectation is that it can be placed in namespace std without conflicting with your program. Case in point: what would happen to your program if your C++ library decided that it needed to define a specialization of the std::pair template for std::pair<std::string, std::string>? To my knowledge, the standard neither requires nor prohibits such a specialization, so the existence of it is left to the implementor's discretion.
Namespaces exist to prevent naming conflicts. In particular, namespace std exists to isolate C++ implementation details from user programs. Adding your code to namespace std destroys that isolation, hence the standard declares it undefined behavior. Don't do it.
(That being said, there is nothing stopping you from writing a wrapper class around std::pair<std::string, std::string> to get the functionality you need. Just do it in your own namespace.)
You need to define a specialization of std::hash for your key type, like so:
#include <unordered_map>
#include <string>
using KeyType = std::pair<std::string, std::string>;
namespace std
{
template<>
struct hash<KeyType>
{
size_t operator()(KeyType const& kt) const
{
size_t hash = 0;
hash_combine(hash, kt.first);
hash_combine(hash, kt.second);
return hash;
}
// taken from boost::hash_combine:
// https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
template <class T>
inline static void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
};
}
int main()
{
std::unordered_map<KeyType, int> us;
return 0;
}
I'm programming in Linux and i have one problem. I have to initialize two vectors with size 'l'. 'l' should be given form command line.
This is code:
#include <iostream>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
int l, m, n, Id;
struct vektori{
std::vector<long double> a(l);
std::vector<long double> b(l);
};
typedef struct vektori* vektor;
int main(int argc, char* argv[]){
if(argc!=4){
cout<<"Greska kod ulaznih parametara"<<endl;
return 0;
}
l=atoi(argv[1]);
m=atoi(argv[2]);
n=atoi(argv[3]);
vektor v;
Id=shmget(IPC_PRIVATE, sizeof(vektori), 0);
v=(vektor)shmat(Id, NULL, 0);
return 0;
}
This are errors:
procesi.cpp:14:29: error: 'l' is not a type
procesi.cpp:15:29: error: 'l' is not a type
Add a constructor to vektor with l as an argument.
Use the argument to initialize the members.
struct vektor // Assuming you meant to use vektor, not vektori
{
vektor(int l) : a(l), b(l) {}
std::vector<long double> a;
std::vector<long double> b;
};
and then, in main, use:
vektor v(l);
This
struct vektori{
std::vector<long double> a(l);
std::vector<long double> b(l);
};
is seen by the compiler as an attempt to declare a and b as member functions. And l is used in place of parameter type. Since l is not a type, these member declarations are ill-formed.
If you wanted to declare a and b as class data members and immediately specify l as an initializer, you have to use {}-based initialization syntax
struct vektori{
std::vector<long double> a{ (long double) l };
std::vector<long double> b{ (long double) l };
};
(An explicit cast is added because of narrowing conversion.)
However, it is not exactly clear why you want to use a global variable to specify the initial size of your vectors. This is not a good idea.
Your struct definition should just declare vectors, you look like you are trying to initiate them. on line 14 and 15 change a(l) to a and b(l) to b
I am looking for a simple way to create an iterator for the values of a map in C++11.
This method should be simple and transparent: simple in that it should be easy to implement, and transparent in that the client should not know the values come from a map, not a set.
This question has been asked several times before. Many of these questions predate C++11 and use boost, which I do not want to use. Some are not simple, John Ahlgren's solution here, http://john-ahlgren.blogspot.com/2013/10/how-to-iterate-over-values-of-stdmap.html , for example requires a page of code to write a custom iterator.
The others are not transparent, i.e., clearly one can write:
map<string,foo> mymap;
for (auto it=mymap.begin();it!=mymap.end();++it){
Foo val= it->second;
...
}
However, I do not want to do this because I do not want the client to have to know of the data representation.
The problem comes up as follows.
I have a bunch of objects uniquely indexed with a long "key". Sometimes I want to manipulate sets of these objects. Other times I want to retrieve an object given its key.
I cannot use the "set" class directly for several reasons, chief among which is that it does not store mutable instances, and these instances must be mutable (except, obviously, for the key).
So, I have decided to store all my objects in a giant global hashtable:
map<long,Foo> all_the_objects;
I then do not work with set<Foo> at all. Instead I work with set<long> and use an adaptor to simulate a set of Foo, i.e.,
class SetOfFoo{
private: set<long> theKeys;
public:
void insert(const & Foo);
size_t size() return theKeys.size();
bool is_member(const & Foo)
{return theKeys.find(Foo.key)
!= theKeys.end;}
Foo & insert(const & Foo val){
long key=val.key;
all_the_objects[key]=val;
return all_the_objects[key];
}
...::iterator begin() {???}
}
In other words, the client of the SetOfFoo class does not know or need to know that SetOfFoo is implemented as as set of keys.
I also cannot just make a Vector myself in the adaptor class, because one cannot store references in C++ collections.
Is it really impossible to make a simple, transparent way to iterate over map<> values? I find it hard to believe, as this is a very common need and is trivial to do in every language I have seen that has hashtables. I just don't understand how this can be hard.
it's pretty trivial.
Here's an extremely simplistic version that minimally solves the problem for a map of ints to strings. You can either rewrite for the types you want or templatise it as you wish.
#include <map>
#include <iostream>
#include <iterator>
#include <string>
#include <algorithm>
struct map_value_iterator : public std::map<int, std::string>::const_iterator
{
map_value_iterator(std::map<int, std::string>::const_iterator src)
: std::map<int, std::string>::const_iterator(std::move(src))
{
}
// override the indirection operator
const std::string& operator*() const {
return std::map<int, std::string>::const_iterator::operator*().second;
}
};
using namespace std;
int main()
{
map<int, string> myMap { {1, "Hello" }, { 2, "World" } };
copy(map_value_iterator(begin(myMap)), map_value_iterator(end(myMap)), ostream_iterator<string>(cout , " "));
cout << endl;
return 0;
}
Program output:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
Hello World
You can do something like the following (C++98):
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include "util/pair_iterator.hpp"
template<class T> inline T const& constify(T& t) { return t; }
int main()
{
using namespace std;
using namespace util;
map<int, string> m;
m[0] = "alice";
m[1] = "bob";
m[2] = "carol";
m[3] = "dave";
m[4] = "eve";
copy(
over_second(m.begin())
, over_second(m.end())
, ostream_iterator<string>(cout, "\n")
);
copy(
over_first(m.begin())
, over_first(m.end())
, ostream_iterator<int>(cout, "\n")
);
// const iterators check
copy(
over_second(constify(m).begin())
, over_second(constify(m).end())
, ostream_iterator<string>(cout, "\n")
);
copy(
over_first(constify(m).begin())
, over_first(constify(m).end())
, ostream_iterator<int>(cout, "\n")
);
}
Here is an implementation:
// util/pair_iterator.hpp
#include <iterator>
#include "boost/iterator/transform_iterator.hpp"
#include "boost/type_traits/remove_reference.hpp"
#include "boost/type_traits/is_const.hpp"
#include "boost/mpl/if.hpp"
namespace util {
namespace aux {
template<class T> struct dereference_type
: boost::remove_reference<typename std::iterator_traits<T>::reference>
{
};
template<class PairT>
struct first_extracter
{
typedef typename boost::mpl::if_<
boost::is_const<PairT>
, typename PairT::first_type const
, typename PairT::first_type
>::type result_type;
result_type& operator()(PairT& p) const { return p.first; }
};
template<class PairT>
struct second_extracter
{
typedef typename boost::mpl::if_<
boost::is_const<PairT>
, typename PairT::second_type const
, typename PairT::second_type
>::type result_type;
result_type& operator()(PairT& p) const { return p.second; }
};
} // namespace aux {
template<class IteratorT>
inline
boost::transform_iterator<aux::first_extracter<typename aux::dereference_type<IteratorT>::type>, IteratorT>
over_first(IteratorT const& i)
{
typedef aux::first_extracter<typename aux::dereference_type<IteratorT>::type> extracter;
return boost::transform_iterator<extracter, IteratorT>(i, extracter());
}
template<class IteratorT>
inline
boost::transform_iterator<aux::second_extracter<typename aux::dereference_type<IteratorT>::type>, IteratorT>
over_second(IteratorT const& i)
{
typedef aux::second_extracter<typename aux::dereference_type<IteratorT>::type> extracter;
return boost::transform_iterator<extracter, IteratorT>(i, extracter());
}
} // namespace util
I have a vector of maps:
typedef map<string, string> aMap;
typedef vector<aMap> rVec;
rVec rows;
How can I remove some elements from rows?
The following code does not work.
struct remove_it
{
bool operator() (rVec& rows)
{
// Validation code here!
}
};
rVec::iterator it = remove(rows.begin(), rows.end(), remove_it());
rows.erase(it, rows.end());
I got the following error.
error: no matching function for call to 'remove(std::vector<s
td::map<std::basic_string<char>, std::basic_string<char> > >::iterator, std::vec
tor<std::map<std::basic_string<char>, std::basic_string<char> > >::iterator, mai
n(int, char**)::remove_it)'
Thanks.
1) First off: please provide a single compilable example.
Your code posted above is problematic as rVec and rowsVector have been interchanged (you would have seen that yourself if you had posted real code).
2) You are using the wrong remove. It should be remove_if
3) It is normal for the functor to be const
4) The operator() should get object of type aMap (as that is what is in your vector) not a reference back to the vector.
5) Don't be lazy add std:: in-front of objects in the standard namespace.
rather than using using namespace std;
#include <map>
#include <vector>
#include <string>
#include <algorithm>
typedef std::map<std::string, std::string> aMap;
typedef std::vector<aMap> rVec;
rVec rows;
struct remove_it
{
// Corrected type here
bool operator() (aMap const& row) const // const here
{
// Validation code here!
return true;
}
};
int main()
{
// _if herer
rVec::iterator it = std::remove_if(rows.begin(), rows.end(), remove_it());
rows.erase(it, rows.end());
}
remove expects a value. You are trying to use a functor, you need to use remove_if for that.
Also, your functor needs to accept an object of type aMap, not rVec.
remove_if is what you want, not remove.