0

I'm trying to recursively get all the values (and keys) of a std::map<string, int> in C++.

By aMap.begin()->first, I get the key of the first element.

By aMap.begin()->second, I get the value of the first element.

Is there a way to get a map that excludes the first value (already used) in the map? The aMap.erase(aMap.begin()) is giving me the error: (rest of map)

Invalid arguments ' Candidates are: std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> mapToCode(std::map<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int,std::less<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>,std::allocator<std::pair<const std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int>>>) ' 

Am I not understanding some basic functionalities of C++ standard map?

Here is the function I'm working with:

using std::map; string mapToCode(map<string, int> aMap) { string returnString = "Dict("; if (aMap.empty()) { return returnString + ")"; } else { string hold = mapToCode(aMap.erase(aMap.begin())) + "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")"; return returnString + hold; } } 

This is the class that's using it:

Dictionary::Dictionary() { } Dictionary::Dictionary(Dictionary dicObject, string key, int value) { std::map<string, int> newDict; newDict[key] = value; newDict.insert(dict.begin(), dict.end()); dict = newDict; } string Dictionary::toCode() { if (empty()) { return "Dictionary()"; } else { return mapToCode(dict); } } 
3
  • 2
    Cannot reproduce the error. Please provide a minimal reproducible example Commented Oct 31, 2019 at 0:30
  • 1
    Can you please post your full code? This code should work just fine. map.erase(map.begin()); There might be something else wrong with your code. Commented Oct 31, 2019 at 0:33
  • I'm using a map to make a Dictionary like object. This is a helper function that takes in the map and returns a string that can be "copied" as code to create a duplicate of the same object before. Commented Oct 31, 2019 at 0:38

2 Answers 2

1

I am not actually sure what you are trying to achieve so I don't know the order to traverse the map :P But I guess this is somewhat close to what you want:

std::string mapToCode(const std::map<std::string, int>& map, std::map<string, int>::iterator it) { std::string returnString = "Dict("; if (it == std::end(map)) { // Not sure if you really wanted to return returnString + ")"; return ""; // returnString; } std::string hold = mapToCode(map, std::next(it)) + "\"" + it->first + "\", " + std::to_string(it->second) + ")"; return returnString + hold; } 

Tested this on this input:

int main() { std::map<std::string, int> map; map.insert(std::make_pair("a", 1)); map.insert(std::make_pair("b", 2)); std::cout << mapToCode(map, map.begin()) << std::endl; return 0; } 

Output is:

Dict(Dict("b", 2)"a", 1) 

Notes: Instead of erasing, which might be expensive, we can use the standard library's std::next to move the iterator to the next place in the container :)

Prefer using std before each call to the standard library and avoid using namespace std.

Notice the const& instead of passing the map by value. It prevents copying the entire map.

For the second part regarding copy constructors:

Dictionary::Dictionary(const Dictionary& other) { // I am assuming that dict is the class variable that you use to store the actual map in the class // Also this "appends" to the existing dictionary // If you want to first delete the old one's data, clear the dict // dict.clear() dict.insert(other.begin(), other.end()); } 
Sign up to request clarification or add additional context in comments.

2 Comments

Do you know what I'm doing wrong with? Dictionary::Dictionary(Dictionary dicObject, string key, int value) { std::map<string, int> newDict; newDict[key] = value; newDict.insert(dict.begin(), dict.end()); dict = newDict; } Sorry, this should work, but I think my constructor is wrong
Are you trying to declare a copy constructor? Just explain what you are trying to do. And if possible edit your main question and post your code there.
0

This line:

string hold = mapToCode(aMap.erase(aMap.begin())) + "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")"; 

doesn't work, because the output of erase() is not the modified map, like you are expecting. And even if it did, you would be accessing aMap.begin() after aMap.erase() modified aMap, which will fail after the last element has been erased. You would need something more like this instead:

string hold = "\"" + aMap.begin()->first + "\", " + std::to_string(aMap.begin()->second) + ")"; aMap.erase(aMap.begin()); hold = mapToCode(tmp) + hold; 

But, why are you using recursion at all? An iterative loop would suffice instead:

string mapToCode(const map<string, int> &aMap) { string returnString = "Dict("; if (!aMap.empty()) { auto toStr = [](const std::pair<const string, int> &aElement) { return "[\"" + aElement.first + "\", " + std::to_string(aElement.second) + "]"; }; auto iter = aMap.begin(); returnString += toStr(*iter); while (++iter != aMap.end()) { returnString += "," + toStr(*iter); } } return returnString + ")"; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.