I want to implement my own "simple" container which will have map properties but also keeps insertion order. I've heard about boost::multi_index but I find it very difficult to understand for what I want.
So I made a templated class:
template<typename KEY, typename VALUE>
class MyMap {
private :
std::vector<KEY> m_keys;
std::vector<VALUE> m_values;
public :
void insert(KEY& key, VALUE& val) {
//Test if key exists //
m_keys.push_back(key);
m_values.push_back(val);
}
/* Other methods like erase/size/operator[]/begin/etc. */
};
Just to test it, I wanted to do something like this:
int main() {
MyMap<string,int> m;
m.insert("test",1);
m.insert("cat",2);
for(auto& item : m) {
cout << item << endl;
cout << m[item] << endl;
}
}
But I keep getting a compilation error on inserts (and [ ]) as it translates my KEY into a basic_string and not a string. It's driving me crazy and I can't find any answer (or any word to properly describe my problem to research for an answer). I guess it has something to do with allocators but I can't manage to understand how to fix it.
How can I make my map do this conversion but also stays general as I will need it with other (own-implemented) classes?
EDIT : After solving "string" problem, I had problems when passing int because it was waiting for an &int. Followed kebs advice and implemented a vector> instead and got rid of conversion problems... :)
You can't build a reference from a const char* (even though it gets casted to a string), try this instead:
template<typename KEY, typename VALUE>
void insert(KEY key, VALUE val) {
m_keys.push_back(key);
m_values.push_back(val);
}
More precisely, the compiler is pretty clear about the problem:
error: invalid initialization of non-const reference of type 'std::basic_string&' from an rvalue of type 'std::basic_string'
m.insert("test",1);
Related
I'm having a problem getting the desired behaviour with array subscription and assignment.
Is there any way to determine whether assignment is used with array subscription?
EDIT
My question probably should have been, can I map [] to a getter, and []= to a setter
// Expect this to return a reference to the value if the key exists,
// or throw an exception if not
myMap["Key"];
// Expect this to always return a reference to the value
// so the value can be populated
myMap["Key"] = "Value";
// The method being used
template <typename K, typename V>
V& MyMap<K, V>::operator[](const K &key)
{
if(this->keyExists(key))
{
return this->find(key);
}
else
{
// At this point I'd like to throw an exception if
// assignment is not being used
this->insert(key, NULL);
return this->pairs[this->itemsStored].val;
}
};
Is there any way to determine whether assignment is used with array
subscription?
Simply, no.
When you do:
myMap["Key"] = "Value";
You're calling two member functions: first, map::operator[] and then -- on a totally different class -- key::operator=. When you simply do myMap["Key"] without the assignment nothing has changed with regards to how you interface with the map. The only difference is what you do next.
You could, I suppose, find some technical hack (like providing a const and non-const version that do different things) which will provide the behavior you are trying to achieve -- but it will be at the cost of poor design. Since you have perscribed within the non-const version that a missing key will be added, subsequently throwing in the non-const version is a major difference. This will be a nightmare to maintain. You will have very strange bugs arise when one version is actually being called when you expected the other to be called. People using your code will be confused and curse your name. Don't do it.
Instead, I suggest you're barking up the entirely wrong tree to begin with. Instead of trying to use operator[] const to determine the existence of a key, why not simply provide a member function that does simply that?
You can, if you wish, have this function throw if the key doesn't exist or simply return a bool.
There's only one way to be sure that no operator= will be called after operator[] (by overloading an operator[] const function), but that wouldn't work every time.
As there's no (easy) way to be able to know when an operator[] is being called with the operator= right after, I'd suggest you to follow the example of std::map by providing two different functions:
operator[], which always return a reference to the object; if the object does not exists, it is created
at, which returns a reference only if the object is already there, otherwise it throws an exception of type std::out_of_range
Yes. Just have the operator[] return a proxy. Something like
the following should work. (I'm using std::map for the
implementation; you can map it to whatever you're using)
template <typename KeyType, typename MappedType>
class MyMap
{
std::map<KeyType, MappedType> myImpl;
// ...
public:
void set( KeyType const& key, MappedType const& value )
{
myImpl[key] = value;
}
MappedType get( KeyType const& key )
{
auto entry = myImpl.find( key );
if ( entry == myImpl.end() ) {
throw DesiredException();
}
return entry->second;
}
class Proxy
{
MyMap* myOwner;
Key myKey;
publc:
Proxy( MyMap& owner, Key const& key )
: myOwner( &owner )
, myKey( key )
{
}
Proxy const& operator=( MappedType const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
operator MappedType() const
{
return myOwner->get( myKey );
}
};
Proxy operator[]( KeyType const& key )
{
return Proxy( *this, key );
}
MappedType operator[]( KeyType const& key ) const
{
return get( key );
}
};
I'm not sure that this is a good idea, however. In general,
having a get( KeyType ) which returns a pointer to the mapped
element, or a null pointer if it isn't present, seems more
natural in C++.
DISCLAIMER : what follows is bad practice, and I do not recommend actually using this. It's merely here to show that what the OP wants is technically possible, even though it's a really bad idea (for reasons I'll go into further).
The bad idea
If you don't mind a bit of hassle, you can have a const and a non-const version of operator[] that behave differently. The const version would throw an exception when accessing a non-existent item, while the non-const version would default-construct a new item in that case.
As a proof of concept :
#include <iostream>
#include <stdexcept>
class Map {
public :
int value;
Map() { value = 42; }
const int& operator[](const size_t& pos) const { if (pos == 0) return value; else throw std::runtime_error("oops"); }
int& operator[](const size_t& pos) { return value; }
};
void showValue(const Map& myMap, size_t pos) {
try {
std::cout << "myMap[" << pos << "] = " << myMap[pos] << std::endl;
}
catch (std::runtime_error e) {
std::cout << "exception when accessing myMap[" << pos << "] : " << e.what() << std::endl;
}
}
int main(void) {
Map myMap;
showValue(myMap, 0);
showValue(myMap, 1);
myMap[0] = 5;
showValue(myMap, 0);
myMap[1] = 10;
showValue(myMap, 0);
return 0;
}
would print :
myMap[0] = 42
exception when accessing myMap[1] : oops
myMap[0] = 5
myMap[0] = 10
But the hassle I mentioned earlier, is to make sure the const version is used whenever the result won't be modified (in the example above, that's done by using a const reference).
Why it's bad
As mentioned at the beginning (and as pointed out by John Dibling in comments), this approach is not recommended. The problem is that :
it's difficult to know which version of operator[] will be called (in those cases where both can be called)
the two versions of operator[] behave differently (one throws an exception while the other would add a new item when called with the same argument)
Combine these two observations, and you get close to unpredictable behaviour, which will hurt you when you least expect it (trust me). And worse, it might be difficult to track down and fix such issues when they occur.
As a rule of thumb, the const and non-const versions of any member function should not differ in their core functionality. Violate that rule, and you invite the wrath of whoever has to maintain the code (and that probably includes your future self).
Any alternatives ?
So, don't do this. Instead, just either do it the same way std::map does (or better yet, just use std::map), or have a contains function you can call to check if an item exists.
I was having trouble with this, and I couldn't find a solution on SO. It took me a while to figure it out so I thought I'd post it, in case its useful for someone else
Problem:
I have a set of functors of different types, which I want to store in a std::map and then call later sort of like a switch statement/factory.
class Foo {
public:
void operator() (int x) {
std::cout << "In foo" << x << std::endl;
}
};
class Bar {
public:
void operator() (int x) {
std::cout << "In Bar" << x << std::endl;
}
};
The map looks like
std::map<int,boost::function<void(int)>> maps;
And the inserts look like
maps.insert(std::make_pair(1,boost::bind(&Foo::operator(),Foo(),_1)));
And you can call it like
auto iter = maps.find(1);
iter->second(123);
Looking at the solution it's quite simple one liner, compared to the mental gymnastics trying to figure it out - oh well :)
What i was trying to do originally was to store boost::signals2::signal objects so I could chain a set of factories,in the map, but I never did figure that out. So for a question, how would I store those instead in a map?
std::map<std::string,boost::signals2::signal<void(int)>> m_factory;
// Create the object I want to store
boost::signals2::signal<void(int)> sig;
sig.connect(Foo());
// This fails
m_factory.insert(std::make_pair("Blah",sig));
but I get
std::pair<_Ty1,_Ty2> std::_Tree<_Traits>::insert(std::pair<const _Kty,_Ty> &&)' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'std::pair<_Ty1,_Ty2> &&
Edit Simplified the example further
Edit 2 - fix bug where I declared map with reference
Further to this, this seems to work fine
typedef boost::signals2::signal<void(int)> Signal;
m_factory["Blah"] = Signal().connect(Foo());
which I thought was logically the same as make_pair?
boost::signals are non-copyable, which makes them not suitable to be used with std containers. You should use pointers (possibly smart pointers) to the signal as in
typedef boost::signals2::signal<void(int)> sig;
typedef std::shared_ptr<sig> pSig;
typedef std::map<int, pSig> map_sig;
void f(int){}
int main(){
pSig s(new sig);
s->connect(f);
map_sig m;
m.insert( map_sig::value_type(1, s) );
}
(you can try the code here).
I want to make a class that will have a single get template method which will receive an std::string to find in a std::map the right variable and return it.
The std::map should store any type of variable, so I used boost::any, so far the std::map looks like that:
std::map<std::string, boost::any> variables_;
for the get function, I tried something like that:
template <typename T>
T get(std::string& parameter)
{
return variables_[parameter];
}
But no lucky, my question is, is that even possible to do? If so, how?
The basic idea is that I dont want to make an specific method to every specific variable in my class, so other classes dont need to know about every get method of it.
Thanks!
ps: For anyone asking why I want this, here is a resume of it, I have a lot of algorithms, that will run in a certain order, and it will use that for the last one already runned algorithm. So, what I want is to make an xml file, that will tell what algorithms will run, in which order and what data it will use from another algorithm.
So, for example, algorithm A have an variable named "threshold", algorithm B need that information, so, normally it will have to ask it from the A using something like A.getThreshold, but as far as I know, I can't call a object function with it name in an string (from the xml file), so my solution would be have only an get function which i pass the variable name I want and that function will return it to me.
An alternative solution would be to "wrap" the boost::any object into another object which can be automatically converted to anything you want. I don't think it's a good practice but it's the best fit according to your question.
class AnyWrapper {
boost::any value;
public:
AnyWrapper(const boost::any& val) : value(val) {}
template<typename T> operator T() {
return boost::any_cast<T>(value);
}
}
And your getter would be something like :
AnyWrapper get(std::string& parameter)
{
return variables_[parameter]; // variables is a std::map<std::string, boost::any>
}
And then you should be able to retrieve your elements like that :
int integerValue = myContainer.get("age");
std::string stringValue = myContainer.get("name");
But again, this is not a clean solution. There is a reason why the boost authors chose to make the any_cast explicit :)
An boost::any value won't implicitly convert to a type T, you have to request that cast manually:
template <typename T>
T get(std::string& parameter)
{
return boost::any_cast<T>(variables_[parameter]);
}
The call will fail with a boost::bad_any_cast exception if the type stored in the any is not exactly T.
You can also return an boost::any. You lose encapsulation of your implementation, but depending on how you use the return value, it may be the better way.
What you want is not possible as you are trying to mix compile time (template) and runtime (map lookup) code.
You either have to make it fully runtime:
struct base_type { virtual ~base_type{} };
struct derived_type: base_type { ... };
std::map<std::string, base_type*> lookup_map;
base_type* get(std::string const& key) { return lookup_map[key]; }
Or fully compile time (boost.fusion example):
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>
namespace bf=boost::fusion;
struct key_a; // analogues of string keys in compile time world
struct key_b;
struct key_c;
typedef bf::map<
bf::pair<key_a, long>,
bf::pair<key_b, double>,
bf::pair<key_c, char const*>
> rtmap_t;
rtmap_t rtmap;
template <class Key>
void set_value(typename bf::result_of::value_at_key<rtmap_t, Key>::type const& val)
{
bf::at_key<Key>(rtmap) = val;
}
template <class Key>
typename bf::result_of::at_key<rtmap_t, Key>::type get_value()
{
return bf::at_key<Key>(rtmap);
}
#include <iostream>
int main()
{
char const* cval = "hello metaprogramming";
set_value<key_a>(123l);
set_value<key_b>(456.789);
set_value<key_c>(cval);
std::cout << get_value<key_a>() << std::endl;
std::cout << get_value<key_b>() << std::endl;
std::cout << get_value<key_c>() << std::endl;
return 0;
}
Considering the information you provided in your question I would choose runtime variant with dynamic polymorphism.
I have a map named valueMap as follows:
typedef std::map<std::string, std::string>MAP;
MAP valueMap;
...
// Entering data.
Then I am passing this map to a function by reference:
void function(const MAP &map)
{
std::string value = map["string"];
// By doing so I am getting an error.
}
How can I get the value from the map, which is passed as a reference to a function?
std::map::operator[] is a non-const member function, and you have a const reference.
You either need to change the signature of function or do:
MAP::const_iterator pos = map.find("string");
if (pos == map.end()) {
//handle the error
} else {
std::string value = pos->second;
...
}
operator[] handles the error by adding a default-constructed value to the map and returning a reference to it. This is no use when all you have is a const reference, so you will need to do something different.
You could ignore the possibility and write string value = map.find("string")->second;, if your program logic somehow guarantees that "string" is already a key. The obvious problem is that if you're wrong then you get undefined behavior.
map.at("key") throws exception if missing key.
If k does not match the key of any element in the container, the
function throws an out_of_range exception.
http://www.cplusplus.com/reference/map/map/at/
The answer by Steve Jessop explains well, why you can't use std::map::operator[] on a const std::map. Gabe Rainbow's answer suggests a nice alternative. I'd just like to provide some example code on how to use map::at(). So, here is an enhanced example of your function():
void function(const MAP &map, const std::string &findMe) {
try {
const std::string& value = map.at(findMe);
std::cout << "Value of key \"" << findMe.c_str() << "\": " << value.c_str() << std::endl;
// TODO: Handle the element found.
}
catch (const std::out_of_range&) {
std::cout << "Key \"" << findMe.c_str() << "\" not found" << std::endl;
// TODO: Deal with the missing element.
}
}
And here is an example main() function:
int main() {
MAP valueMap;
valueMap["string"] = "abc";
function(valueMap, "string");
function(valueMap, "strong");
return 0;
}
Output:
Value of key "string": abc
Key "strong" not found
Code on Ideone
The main problem is that operator[] is used to insert and read a value into and from the map, so it cannot be const.
If the key does not exist, it will create a new entry with a default value in it, incrementing the size of the map, that will contain a new key with an empty string ,in this particular case, as a value if the key does not exist yet.
You should avoid operator[] when reading from a map and use, as was mention before, map.at(key) to ensure bound checking. This is one of the most common mistakes people often do with maps. You should use insert and at unless your code is aware of this fact. Check this talk about common bugs Curiously Recurring C++ Bugs at Facebook
How can I get the value from the map, which is passed as a reference to a function?
Well, you can pass it as a reference. The standard reference wrapper that is.
typedef std::map<std::string, std::string> MAP;
// create your map reference type
using map_ref_t = std::reference_wrapper<MAP>;
// use it
void function(map_ref_t map_r)
{
// get to the map from inside the
// std::reference_wrapper
// see the alternatives behind that link
MAP & the_map = map_r;
// take the value from the map
// by reference
auto & value_r = the_map["key"];
// change it, "in place"
value_r = "new!";
}
And the test.
void test_ref_to_map() {
MAP valueMap;
valueMap["key"] = "value";
// pass it by reference
function(valueMap);
// check that the value has changed
assert( "new!" == valueMap["key"] );
}
I think this is nice and simple. Enjoy ...
Although it's kinda late but I am still gonna answer, thanks to previous answers on this question i was able to forge this class which reuse pointers and values, it creates two maps to store data, Here the code if anybody interested..
template<class T1, class T2> class Bimap
{
std::map<T1, T2*> map1;
std::map<T2, T1*> map2;
public:
void addRow(T1 &t1, T2 &t2){
map1.insert(make_pair(t1, &t2));
map2.insert(make_pair(t2, &t1));
}
T2* findForward(T1 t1){
T2* value = map1.find(t1)->second;
return value;
}
T1* findBackward(T2 t2){
T1* value = map2.find(t2)->first;
return value;
}
};
Using class:
//Init mapp with int,int
Bimap<int,int> mapp;
//Add a row(Record) in bimap
int a = 5;
int b = 7002;
mapp.addRow(a, b);
//Print a record
int *ans= mapp.findForward(a);
cout<<"Bimap Returned:"<<*ans<<endl;
string var;
void setvar(string ivar)
{
var=ivar;
}
string getVar() const
{
return var;
}
as same way how can i write setter and getter method for a map like this
std::map varmap;
You can write a getter or setter for a field that's a std::map just as you would any other field - just have the getter return a std::map and have the setter accept a std::map.
Of course, if you have a field that's a std::map that you're trying to use getters and setters on, that might suggest that there's a better way to structure the program. Can you provide more details about what you're trying to do?
EDIT: The above answer is for a slightly different question than the one you asked. It seems like what you're interested in is
Given a class with a std::map as a data member, write a function to set a given key/value pair and a function to return the value associated with a given key.
The setter logic for this is not too hard - you just write a function that takes in the key and value and associates the key with the value. For example:
void put(const string& key, const string& value) {
varmap[key] = value;
}
Writing a getter is trickier because there's no guarantee that there's a value associated with a particular key. When this happens, you have multiple options.
You could return a sentinel value. For example, you might return an empty string if the given value isn't stored in the map anywhere. This makes the code for using the function easier to read, but risks using an invalid value in code.
You could throw an exception. This would be good if it represents a serious error for the given value not to exist. This has the drawback that if you look up a value, you always need to try/catch the logic to avoid propagation of errors.
You could associate a default value with the key, then hand that back. If you're writing a program that represents a music library, for example, you might hand back "(none)" or "(unknown)" if you tried to look up the artist for a song on which you have no data, for example.
No one of these approaches works best, and you'll need to think over which is most appropriate to your particular circumstance.
Entries in a std::map<Key, Value> must have a key and a value. The normal way of getting and setting them is:
my_map[a_key] = new_value; // set
do_something_with(my_map[a_key]); // get and use...
If you want to add new functions, they probably wouldn't look like what you're proposing because:
your set is only given one parameter despite needing a key and value (admittedly, you could adopt some convention like having the first ':' or '=' separate them), and
the get() function doesn't provide any key.
You could instead have something more like:
void set(const Key&, const Value&);
std::string get(const Key&) const;
But, even if you have write permissions to do so, you shouldn't add that directly in the map header file - all C++ programs compiled on that computer will share that file and won't expect it to be modified. Any small mistake could cause trouble, and if you ship your program to another computer you won't be able to compile it there without making a similar modification - if that computer uses a different C++ compiler the necessary details of that modification may be slightly different too.
So, you can either write your own (preferably templated) class that derives from (inherits) or contains (composition) a std::map, providing your functions in your custom class. An inheritance based solution is easier and more concise to write:
template <typename Key, typename Value>
struct My_Map : std::map<Key, Value>
{
My_Map(...); // have to provide any non-default constructors you want...
void set(const Key& key, const Value& value) { operator[](key) = value; }
// if you want entries for non-existent keys to be created with a default Value...
Value& get(const Key& key) { return operator[](key); }
--- OR ---
// if you want an exception thrown for non-existent keys...
Value& get(const Key& key) { return at(key); }
const Value& get(const Key& key) const { return at(key); }
};
This is slightly dangerous if you're planning to pass My_Maps around by pointer and accidentally end up with a "new My_Map" pointer that's later deleted as a std::map pointer, as in:
void f(std::map<int, string>* p) { /* use *p */ delete p; }
My_Map<int, string>* p = new My_Map<int, string>;
f(p);
Still, in most programs there's no real danger of accidentally disposing of a map like this, so go ahead and do it.
Further, and this is the kind of thinking that'll make me unpopular with the Standard-fearing purists around here - because My_Map hasn't added any data members or other bases, the std::map<> destructor probably does all the necessary tear-down even though it's technically Undefined Behaviour. I'm NOT encouraging you to ignore the issue (and would consider it unprofessional in a job requiring robustness), but you can at least rest a little easier. I'd be curious to hear from anyone with any compiler/settings where it demonstrably doesn't operate safely.
If you use composition, you'll have to write your own "forwarding" functions to let you use My_Map like a std::map, accessing iterators, find, erase, insert etc.. It's a pain.
Setter and getter for std::map is no different except that you need to pass the necessary parameters for the setter. Assume if I have a struct and has a member variable whose type is std::map, whose key is of type char and data is of type int. Method signatures would be of the format -
void setEncode( char* key, int* data, const int& size ); Because, std::map requires a key, data and sizes of these arrays being passed. With out knowing size, it is unknown as how far to insert the elements in to the container.
std::map<char, int> getEncode() const ; const key word signifies it a non-modifying member function. Because it's functionality is to just return a variable of type std::map.
Example -
struct myMap
{
std::map<char, int> encode;
void setEncode( char* key, int* data, const int& size );
std::map<char, int> getEncode() const ;
};
void myMap::setEncode( char *key, int* data, const int& size )
{
int i=0;
while( i < size )
{
encode.insert(std::pair<char, int>(key[i], data[i]));
++i ;
}
}
std::map<char, int> myMap::getEncode() const
{
return encode;
}
Results IdeOne. This should give you an idea, but should also follow the general rules what #templatetypedef, #tony suggested.
Do you want to set a key value pair in an existing map(probably that's what you want) or create a new map itself?
void setvar(string key, int value)
{
myMap[key] = value;
}
int getVar(string key) const
{
return myMap[key];
}
where int and string are interchangeable
For latter you'll probably have to interate over all map values for setting and getter should be just to return that map pointer.