struct MapInserter
{
private:
int count;
public:
explicit MapInserter()
: count(0)
{
}
std::pair<int, std::string> operator()(std::string& value)
{
return std::make_pair(count++, value);
}
};
vector<std::string> words = { "one", "two", "three","four","five" };
std::map<int, std::string> map;
MapInserter inserter;
transform(words.begin(), words.end(), map.begin(), inserter);
for (auto it = map.begin(), end = map.end(); it != end; ++it)
cout << it->first << " : " << it->second << endl;
return 0;
that's the code. VS returns a compile error regarding l-value specifies const object.
Clicking the error moves you to the following code in a file named utility
template<class _Other1,
class _Other2>
_Myt& operator=(pair<_Other1, _Other2>&& _Right)
{ // assign from moved compatible pair
first = _STD forward<_Other1>(_Right.first);
second = _STD forward<_Other2>(_Right.second);
return (*this);
}
at first, i've had the operator() take const std::string& so I removed the const, because it's obviously talking about the make_pair function. But it still hasn't gone away. Can anyone point me to what this error is about?
The problem is that std::transform() will try to assign to existing elements of the target container. Keys of a map are constant and cannot be assigned to, which is why you're getting a compiler error. But even if they were, you'd get undefined behavior at run-time here, because the target container is empty, and std::transform() would expect it to contain as many elements as the input range.
You should use std::inserter() to create an inserter iterator, like so:
vector<std::string> words = { "one", "two", "three","four","five" };
std::map<int, std::string> map;
MapInserter inserter;
transform(words.begin(), words.end(), std::inserter(map, map.begin()), inserter);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is a live example.
Moreover, taking the value string by mutable lvalue reference in the call operator of your MapInserter is not a good idea: you don't want the argument to be modified, so you should either take it by const& or - my advice - take it by value and then move it into the returned pair, like so:
std::pair<int, std::string> operator()(std::string value)
{
return {count++, std::move(value)};
}
Since std::pair's constructor is not explicit, you do not even need the call to std::make_pair() in this case.
Related
#include <iostream>
#include <map>
int main(void) {
std::map<char, int> mapint;
mapint.insert({'a', 1});
mapint.insert({'b', 2});
// subscript operator is overloaded to return iterator.second (the value with key 'a')
int ex = mapint['a'];
std::cout << ex << std::endl;
// Why does this NOT traslate to 1=10 ?
// instead it replaces or creates pair <'a',10>...
mapint['a'] = 10;
for (auto i : mapint) {
std::cout << i.first << "," << i.second << std::endl;
}
// OUTPUT
// 1
// a,10
// b,2
return 0;
}
How is the map operator being overloaded? I tried looking at the code for map but i couldn't find anything to answer my question...
I want to make something similar for one of my classes and i think figuring this out should help alot!
It basically just builds on top of existing methods found within map. It is implemented along the lines of...
template<typename Key, typename Value>
struct map {
// This operator cannot be declared 'const', since if the key
// is not found, a new items is automatically added.
Value& operator [] (const Key& key) {
// attempt to find the key
auto iter = find(key);
// if not found...
if(iter == end()) {
// insert new item (with a default value to start with)
iter = insert(std::make_pair(key, Value()));
}
// return reference to the data item stored for 'key'
return iter->second;
}
};
To overload the [] operator you can do as follows (in pseudo-code):
struct A
{
your_return_type operator[](your_argument_list)
{
your implementation
}
};
If you want to return a reference to some class member, then you may have to implement 2 versions of this operator, one const, which returns a non-modifiable reference, and one non-const, which returns a modifiable refence.
struct A
{
your_modifiable_return_type_ref& operator[](your_argument_list)
{
your implementation
}
const your_non_modifiable_return_type_ref& operator[](your_argument_list) const
{
your implementation
}
};
I'm trying to figure out a nice way to find the index of a certain object in a vector - by comparing a string to a member field in the object.
Like this:
find(vector.begin(), vector.end(), [object where obj.getName() == myString])
I have searched without success - maybe I don't fully understand what to look for.
You can use std::find_if with a suitable functor. In this example, a C++11 lambda is used:
std::vector<Type> v = ....;
std::string myString = ....;
auto it = find_if(v.begin(), v.end(), [&myString](const Type& obj) {return obj.getName() == myString;})
if (it != v.end())
{
// found element. it is an iterator to the first matching element.
// if you really need the index, you can also get it:
auto index = std::distance(v.begin(), it);
}
If you have no C++11 lambda support, a functor would work:
struct MatchString
{
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Type& obj) const
{
return obj.getName() == s_;
}
private:
const std::string& s_;
};
Here, MatchString is a type whose instances are callable with a single Type object, and return a boolean. For example,
Type t("Foo"); // assume this means t.getName() is "Foo"
MatchString m("Foo");
bool b = m(t); // b is true
then you can pass an instance to std::find
std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString));
In addition to the Lambda and the handwritten functor used by juancho, you have the possibility to use boost::bind (C++03) or std::bind (C++11) and a simple function:
bool isNameOfObj(const std::string& s, const Type& obj)
{ return obj.getName() == s; }
//...
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&isNameOfObj, myString, boost::placeholders::_1));
Or, if Type has a method isName:
std::vector<Type>::iterator it = find_if(v.begin(), v.end(),
boost::bind(&Type::isName, boost::placeholders::_1, myString));
This is just for completeness. In C++11 I'd prefer Lambdas, in C++03 I'd use bind only if the comparison function itself exists already. If not, prefer the functor.
PS: Since C++11 has no polymorphic/templated lambdas, bind still has it's place in C++11, e.g. if the parameter types are unknown, hard to spell, or otherwise not easy to deduce.
A simple iterator may help.
typedef std::vector<MyDataType> MyDataTypeList;
// MyDataType findIt should have been defined and assigned
MyDataTypeList m_MyObjects;
//By this time, the push_back() calls should have happened
MyDataTypeList::iterator itr = m_MyObjects.begin();
while (itr != m_MyObjects.end())
{
if(m_MyObjects[*itr] == findIt) // any other comparator you may want to use
// do what ever you like
}
This is my declaration of the set:
set< vector<string> >* tuples = new set< vector<string> >();
And this is how I am trying to iterate through it:
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); it++){
if(it[column] == value){
rowResults->insert(*it);
}
}
but I get an error
no match for ‘operator[]’ (operand types are ‘std::set<std::vector<std::__cxx11::basic_string<char> > >::iterator {aka std::_Rb_tree_const_iterator<std::vector<std::__cxx11::basic_string<char> > >}’ and ‘int’)
if(it[column] == value){
^
You're applying [] to the iterator instead of to the object to which it points. You need to dereference the iterator (and mind operator precedence!):
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); ++it){
if((*it)[column] == value){
rowResults->insert(*it);
}
}
Note that with iterators, it's better to use ++it instead of it++ in loops, since the latter can be less efficient under insufficient optimisation.
it is an iterator, not the vector object itself. To access the vector object just use *it
Even better: get rid of the confusing iterator type by defining a reference (here constant ref since we don't seem to need a non-const) to the element itself.
for(set< vector<string> >::iterator it = tuples->begin(); it != tuples->end(); it++){
const vector<string> &v = *it; // more readable
if(v[column] == value){
rowResults->insert(v);
}
}
as no decent C++ answer cannot not mention the "new" C++11, note that if you use -std=c++11 option, the syntax is much better to iterate on a list
for(auto v : *tuples)
{
if(v[column] == value){
rowResults->insert(v);
}
}
You may avoid iterator with something like:
std::set<std::vector<std::string>>
computeRowResult(const std::set<std::vector<std::string>>& input,
int column,
const std::string& value)
{
std::set<std::vector<std::string>> rowResults;
for (const auto& v : input) {
if (v[column] == value) {
rowResults.insert(v);
}
}
return rowResults;
}
or avoiding the manual loop with
std::set<std::vector<std::string>>
computeRowResult(const std::set<std::vector<std::string>>& input,
int column,
const std::string& value)
{
std::set<std::vector<std::string>> rowResults;
std::copy_if(input.begin(), input.end(),
std::inserter(rowResults, rowResults.end()),
[&](const auto& v) { return v[column] == value; });
return rowResults;
}
Demo
I'm not sure if this is an error with my C++ syntax, or if this is something that cannot be accomplished at all.
I want to define a class that takes a std::map as a constructor argument. I then want to create an instance of that class by passing a "temporary" (appropriate to call this "rvalue"?) std::map. I.e. I do not want to create an lvalue std::map and then pass that to the constructor.
Can this be accomplished? I have tried the following (commented lines show failed attempts)
#include <map>
#include <string>
#include <iostream>
class Test
{
public:
Test(std::map<int,char>& rMap)
{
std::map<int,char>::iterator iter;
for (iter = rMap.begin(); iter != rMap.end(); ++iter)
{
mMap[iter->first] = mMap[iter->second];
}
}
virtual ~Test(){}
protected:
std::map<int, char> mMap;
};
int main()
{
std::cout << "Hello world!" << std::endl;
//Test test({1,'a'}); // Compile error.
//Test test(std::map<int,char>(1,'a')); // Also compile error.
//Test test(std::map<int,char>{1,'a'}); // Yet again compile error.
return 0;
}
This is my compiler:
g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11)
Compile errors can be posted upon request, but I'm not sure if they would be useful if my problem is syntactic.
Thank you.
Do
Test(std::map<int, char> rMap) : mMap(std::move(rMap)) {}
or
Test(std::map<int, char>&& rMap) : mMap(std::move(rMap)) {}
or
Test(const std::map<int, char>& rMap) : mMap(rMap) {}
Temporary cannot bind to non const l-value reference.
And use it as
Test test({{1,'a'}});
Test test2({{1,'a'}, {2, 'b'}});
Yes but your constructor takes an lvalue reference. It must instead be a reference-to-const, or an rvalue reference.
Just like with any other type.
#include <map>
class Test {
public:
Test(std::map<int,char> const& cMap)
{
std::map<int,char>::const_iterator iter;
for (iter = cMap.cbegin(); iter != cMap.cend(); ++iter)
{
mMap[iter->first] = mMap[iter->second];
}
}
virtual ~Test() { }
protected:
std::map<int, char> mMap;
};
int main() {
Test test(std::map<int,char>({{1,'a'}, {2, 'b'}}));
return 0;
}
Some explanations:
You need Test(T), Test(const T&) or Test(T&&) constructor if you want to pass temporary object (like std::map<int,char>()) into it. Don't forget what T&& constructors is used for. If in doubt do not use them.
If you work with const std::vector/map/list/... you can't use .begin() and .end() to iterate through elements -- use .cbegin() and .cend(). Moreover it will become more easy with auto. Just try
for (auto iter = rMap.cbegin(); iter != rMap.cend(); ++iter)
instead
std::map<int,char>::const_iterator iter;
for (iter = rMap.cbegin(); iter != rMap.cend(); ++iter)
To initialize std::map use "double-bracket" initializers like {{1,'a'}, {2, 'b'}} -- {{key, value}, {second_key, second_value}, ...} this construction is available because
1) std::map has this constructor:
map( std::initializer_list<value_type> init,
const Compare& comp = Compare(),
const Allocator& alloc = Allocator() );
// see http://en.cppreference.com/w/cpp/container/map/map
2) inner braces {1,'a'} is interpreted as value_type constructor call. And value_type for std::map<int, char> is std::pair<int, char>.
P. S. don't forget that std::map<int,char>() and std::map<int,char>{} constructor calls are equal. That means you can drop front brackets: std::map<int,char>({{1,'a'},{2,'b'}}) --> std::map<int,char>{{1,'a'},{2,'b'}}
You should use:
class Test
{
public:
Test(const std::map<int,char>& rMap) : mMap(rMap)
{}
Test(std::map<int,char>&& rMap) : mMap(std::move(rMap))
{}
virtual ~Test(){}
protected:
std::map<int, char> mMap;
};
This provides two constructors: one which takes a const lvalue reference and copies its contents into mMap and one which takes an rvalue reference and moves its contents into mMap. This allows you to construct a Test instance using either a named std::map or a temporary:
int main()
{
std::map<int,char> m{{1, 'a'}, {2,'b'}};
Test t1{m};
Test t2{{{1, 'a'}, {2, 'b'}}};
}
This lets you avoid unnecessary copies when you can, but still lets you make a copy of the map when you need to.
basically, I have the
map<std::string, int>
so if i have
foo 5
bar 10
jack 3
in the map, I want to display it (notice the reverse order)
bar 10
foo 5
jack 3
And every time it is updated, I want iterate through all the elements, cout them, sorted by value. What is the good way to implement that? should I provide a comparator to the constructor?
I want to note that values in the map will be updated at least 100 million times, so efficiency is crucial, where as extra-space is no problem
Please no Boost solutions...thx
struct keyval_t { std::string key; int val; };
int operator<(const keyval_t &a, const ketval_t &b)
{ return a.val<b.val || (a.val==b.val && a.key<b.key); }
Then you need one map and one set:
map<std::string, int>; set<keyval_t>;
On update, you need to look up the map first to determine the key-value pair and then update both map and set. On printing, you just iterate through the set. In terms of theoretical time complexity, this is optimal. It doubles the memory, though. Does this meet your goal?
To reduce memory, you may consider the following:
map<std::string,uint64_t>; set<uint64_t>;
The value of the map (also the key of the set) is: (uint64_t)val<<32|counter, where counter is something that differentiates identical values. For example, whenever you insert a key, increase the counter by 1. You do not need to update the counter when you update the value. If you do not like uint64_t, use pair<int,int> instead. This solution is also faster as it avoids comparisons between strings.
If you want a performant map sorted by both key and value, you want Boost MultiIndex, it gets updated (resorted) on every update (which you have to do manually) and has a good documentation.
The previous responses have the inconvenience not to take into account the initial requirements (the key is std::string and the value is int).
EDITED: following the comments, I suppose presenting it directly with a Bimap is better :)
So here we go, right in!
#include <boost/bimap.hpp>
class MyMap
{
struct name {};
struct value {};
typedef boost::tagged<name, std::string> tagged_name;
typedef boost::tagged<value, int> tagged_value;
// unordered_set_of: guarantees only unicity (not order)
// multi_set_of: guarantees only order (not unicity)
typedef boost::bimap< boost::unordered_set_of< tagged_name >,
boost::multi_set_of< tagged_value,
std::greater< tagged_value >
>
> impl_type;
public:
// Redefine all usual types here
typedef typename impl_type::map_by<name>::const_iterator const_iterator;
typedef typename impl_type::value_type value_type;
// Define the functions you want
// the bimap will not allow mutators because the elements are used as keys
// so you may want to add wrappers
std::pair< iterator, bool > insert(const value_type & x)
{
std::pair< iterator, bool > result = m_impl.insert(x);
if (result.second) this->display();
return result;
} // insert
iterator insert(iterator position, const value_type & x)
{
iterator result = m_impl.insert(x);
this->display();
return result;
} // insert
template< class InputIterator >
void insert(InputIterator first, InputIterator last)
{
m_impl.insert(first, last);
this->display();
} // insert
private:
void display() const
{
// Yeah I know about std::for_each...
typedef typename impl_type::map_by<value>::const_iterator const_it;
for (const_it it = m_impl.begin(), end = m_impl.end(); it != end; ++it)
{
// Note the inversion of the 'second' and 'first',
// we are looking at it from the right
std::cout << it->second << " " << it->first << std::endl;
}
}
impl_type m_impl;
}; // class MyMap
Here you go.
I strongly suggest that you consult the bimap documentation though. There are a lot of possibilities for storing (set_of, unordered_set_of, unconstrained_set_of, the muli variants, the list_of variant...) so there is probably one that could do what you want.
Then you also have the possibility to just sort each time you display:
#include <set>
#include <map>
// Just use a simple std::map<std::string,int> for your impl_type
// Mutators are allowed since the elements are sorted each time you display
struct Comparator
{
bool operator(const value_type& lhs, const value_type& rhs) const
{
return lhs.second < rhs.value;
}
};
void display() const
{
typedef std::multi_set<value_type, Comparator> sort_type;
sort_type mySet;
std::copy(m_impl.begin(), m_impl.end(), std::inserter(mySet, mySet.end()));
for (sort_type it = mySet.begin(), end = mySet.end(); it != end; ++it)
{
std::cout << it->first<< " " << it->second << std::endl;
}
}
It should be easier to understand my point now :)
Well, you have to sort by key. The easiest way to "sort by value" is to use a multimap with the key and value switched. So here's a way to do that (note -- i don't have access to a compiler right now, so if it doesn't compile, I'm sorry):
#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <utility>
typedef std::multimap<int, std::string, std::greater<int> > MapType;
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
void display_insert(MapType& m, const std::string& str, int val)
{
m.insert(std::make_pair(val, str));
std::for_each(m.begin(), m.end(), MapKeyOutput());
}
int main()
{
MapType m;
display_insert(m, "Billy", 5);
display_insert(m, "Johnny", 10);
}
You could also make a map class that uses a multimap internally, I just didn't want to type it out. Then display_insert would be some member function instead. This should demonstrate the point, though. Points of interest:
typedef std::multimap<int, std::string, std::greater<int> > MapType;
Note the comparator is greater<int> to sort descending. We're using a multimap so more than one name can have the same number.
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
This is a function object to output one element in the map. second is output before first so the order is what you want.
std::for_each(m.begin(), m.end(), MapKeyOutput());
This applies our function object to every element in m.