How to convert an integer to a string?

I'm trying to use a multimap in which the key I get from the integer in a loop. In other words, I want my map to look like:
1
2
1 => 'data1'
2 => 'data2'

etc.

However, I've made the keys be strings on purpose, as in a later stage of the program, I want to assign new keys which are strings.

When I simply do
1
2
3
4
5
6
7
8
9
10
for(int i=0; i<input; i++) {
	cout << "Client number " << i + 1 << endl;
	client newClient;
	cout << "Name: ";
	getline(cin, newClient.name);
	cout << "Phone: ";
	getline(cin, newClient.phone);
	cout << endl;
	clients.insert(pair<string,client>(i, newClient));
}

(clients is defined as multimap<string, client> clients;)
I get an error saying
Error 1 error C2665: 'std::pair<_Ty1,_Ty2>::pair' : none of the 3 overloads could convert all the argument types X:\XXX\TEST.cpp 118

(line 118 is the clients.insert() part)

I tried explicitly casting the integer in a few ways like "(string) i" and "string(i)" and even creating another string variable and assigning "i" to it, but I always got some sort of a compilation error related to the type casting.

I searched the forum and found only the following archived topic:
http://www.cplusplus.com/forum/beginner/523/
but the only thing which it reveals is the other way around - casting a string into an integer. Even though the OP asked for the other way around, the question never got answered.
It works both ways.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <sstream>
#include <stdexcept>
#include <string>

std::string IntToStr( int n )
  {
  std::ostringstream result;
  result << n;
  return result.str();
  }

int StrToInt( const std::string& s )
  {
  int result;
  std::istringstream ss( s );
  ss >> result;
  if (!ss) throw std::invalid_argument( "StrToInt" );
  return result;
  }

Remember that a stringstream is a standard I/O stream, and you can do all the usual I/O stuff with it.

Hope this helps.
Last edited on
Hm. Interesting.... and works like a charm. Thanks. I'll keep your advice (and functions ;-) ) in mind.

One question though. What's the difference between ostringstream and stringstream? I notice they both compile and behave equivalently, but the reference doesn't seem to clear up what is the difference between them. Both of their descriptions are the same that is.
Last edited on
The stringstream inherits from both istringstream and ostringstream, so it can do anything either ancestor can do.

(I usually just use stringstream, but lately I've gotten into the habit of writing things a little more instructively than strictly necessary... :->)
Makes sence I guess.

Now that this issue is settled with, I have another (probably more challenging) problem. As I said, I want to change the key later in the program. I thought this would be as simple as iterating over the multimap and assigning each "first" a new value, but for some reason, I get compilation errors. The code in question is:
1
2
3
for (it=clients.begin(); it!=clients.end(); it++) {
	(*it).first.assign((*it).second.phone);
}

("it" is earlier defined as "multimap<string,client>::iterator it;")

When I try this, I get
Error 1 error C2663: 'std::basic_string<_Elem,_Traits,_Ax>::assign' : 7 overloads have no legal conversion for 'this' pointer X:\XXX\TEST.cpp 66

(line 66 is the one inside the loop)

I tried various other methods for adjusting the key, and I failed. Are keys actually adjustable to begin with?

I guess if not, I could just make another multimap, iterate over the first in order to populate each key and value, and then replace the old one, but I'm really hoping there's a more straight forward way than this.
Last edited on
Hmm, I'm not sure. Are you certain that second.phone is a (std::string) or a (char*)?

Did you try it->first.assign(it->second.phone);

If neither of those are right I'll have to try doing it myself. (AFAIK you can assign to first.)
Well, I tried it now, and that too failed with a similar the same error.

Yes, I'm absolutely certain that second.phone is std::string. It's such by definiton and there's no other phone available.

Here's a more complete source code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>
#include <limits>
#include <map>
using namespace std;
int streamLimit = numeric_limits<streamsize>::max();

struct client {
	string phone;
	string name;
};
int numOfClients;
multimap<string, client> clients;
multimap<string, client>::iterator it;
void outclients() {
	for (it=clients.begin(); it!=clients.end(); it++)
		cout << (*it).first << " => " << (*it).second.name << endl;
}
void sortByPhone() {
	for (it=clients.begin(); it!=clients.end(); it++) {
		it->first.assign(it->second.phone);
	}
	outclients();
}
string IntToStr(int n) {
	stringstream result;
	result << n;
	return result.str();
}
int StrToInt(const std::string& s) {
	int result;
	std::istringstream ss(s);
	ss >> result;
	if (!ss) throw std::invalid_argument("StrToInt");
	return result;
}
int main()
{
	while(true) {
		try {
			cout << "How many clients would you like to enter? (must be between 1 and 50)" << endl;
			string inputString;
			cin >> inputString;
			stringstream ss(inputString);
			ss.setf(ios_base::skipws);
			int input;
			if((ss >> input).fail()) {
				throw exception("You must enter digits.");
			}
			cin.ignore(streamLimit, '\n');
			if (!(1 <= input && input <= 50)) {
				throw exception("You may only enter between 1 and 50 clients.");
			}
			numOfClients = input;
			cout << "You're about to enter " << input << " clients." << endl << endl;
			for(int i=0; i<input; i++) {
				cout << "Client number " << i + 1 << endl;
				client newClient;
				cout << "Name: ";
				getline(cin, newClient.name);
				cout << "Phone: ";
				getline(cin, newClient.phone);
				cout << endl;
				clients.insert(pair<string,client>(IntToStr(i), newClient));
			}

			cout << endl << "In order of input: " << endl;
			outclients();

			cout << endl << "In order of phone number: " << endl;
			sortByPhone();

			system("PAUSE");
			return 0;
		}
		catch(exception& e) {
			cout << "Error: " << e.what() << endl;
		}
		catch(...) {
			cout << "Unknown error..." << endl;
		}
		cout << "The program will restart..." << endl << endl;
		cin.clear();
	}
}

(I also have some additional functions and comments, but they are omitted for clarity and none of the omitted stuff is ever used)

The problematic area is the sortByPhone() function.
Last edited on
Yeah, it is complaining that you can't assign to first:
a.cpp:23: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(std::string&) const'


The const on the end there means that the method it is looking for doesn't change the target object --which is at odds to what assign() does... I'll have to think a bit about how to get around that. Chances are that you'll just have to create a new multimap and swap content before returning. http://www.cplusplus.com/reference/stl/multimap/swap.html

Also, you forgot to #include <stdexcept> .

And on lines 50 and 54, std::exception() doesn't take any arguments. You can use std::runtime_error instead if you like, or just throw the char string itself:
1
2
3
4
5
6
7
try {
  throw "Throw me";
  }
catch (const char* s)
  {
  cout << "Caught \"" << s << "\"\n";
  }

Alas.
Yeah. Doing that is just what I was afraid of. Too bad there isn't any other way. Oh well...

As far exceptions go... Strange. I've been using them ever since I started learning C++ ("very recently" that is) and I've never had to include them. I thought they're an internal part of the language too.

My compiler is Microsoft Visual Studio 2005 Professional though. I believe this may be the reason.

I used std::exception() because I wanted to have a generic error handler (I don't really need to handle every error in a special way), and by convention, all exceptions extend std::excetpion. If I was to throw the string, I'd have to create a special char handler + this one in case an exception was thrown at an unexpected place in the program.

[edit]Wow. The code for this is actually less than what I imagined. Only two lines longer:
1
2
3
4
5
6
7
8
void sortByPhone() {
	multimap<string, client> clientsByPhone;
	for (it=clients.begin(); it!=clients.end(); it++) {
		clientsByPhone.insert(pair<string, client>((*it).second.phone, (*it).second));
	}
	clients.swap(clientsByPhone);
	outclients();
}

[/edit]
Last edited on
:-)

The <stdafx.h> includes <stdexcept> I think...

Exceptions are part of the language, but std::exception is not --it is part of the STL. <exception> declares std::exception, from which you can derive new exception types, and <stdexcept> declares the exceptions that the STL will throw.

So, essentially, that (...) catches anything not derived from std::exception.

The std::runtime_error is exactly for runtime exceptions, so you can utilize it without guilt.

Or you can derive your own custom exception:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <exception>
struct fooey: std::exception
  {
  std::string message;
  explicit fooey( const std::string& message ):
    message( message )
    { }

  const char* what() const throw ()
    {
    return message.c_str();
    }
  };

This is useful if you always expect to catch your custom exception before it gets to (...).

Or, if you also want your custom exception to be able to be caught by standard exception handlers:
1
2
3
4
5
6
7
#include <stdexcept>
class fooey: public std::runtime_error
  {
  explicit fooey( const std::string& message ):
    std::runtime_error( message )
    { }
  };

This way, you can catch either by explicit reference to your class type or by letting it pass up the chain to more general exception types.

Hope this helps.
I've done the same inheritance thing you describe in PHP, only there you don't have a runtime_error class. I used Exception here as this is what I used in PHP (old habits die hard you know).

runtime_error seems to derive from Exception (it was caught by my generic exception handler), so I'll probably use that from now on (unless I define my own class of course). Thanks for the tip.

As for VS2005, no, stdafx.h doesn't #include <exception>, but I added it anyway to remind me I need it.

Besides, I have an exam coming up tomorrow where all of what I just learned will be put to the test (I'll have to write a similar program on paper in 4 hours... yuk). I'm betting I'll be having less points if I forget to #include <exception>.
Last edited on
You seem to have a very good grasp of what you are doing. I'm sure you'll do fine. (At least an 'A'.)
Last edited on
OK. One last problem, related to this. One of the tasks in the sample exam program I'm duplicating (with STL, unlike the array methods that are used as the sample solution) is to sort people by the time they've talked over the phone. When the time is the same, the clients must be sorted depending on their "group" (defined by the third character in their phone number).

But as far as I've noticed, multimaps' sort function can only accept the two keys and there's no way to know for sure which values are associated with them. Even if I loop over the original map in search for the keys, the fact that they can repeat means I may compare two wrong instances.

So... without the arcane bubble method, how could I have a second sorting key that is based on the value of a multimap item?

[edit]Nevermind... I'm going to bed now, as it's very late already. Hopefully among the tasks at the real exam, they won't require a second sorting key. If they do, I'm out of points at that part.[/edit]
Last edited on
Personally, I think the idea of sorting a map to be very strange... The whole point of the structure is that it appears unsorted. (It is, underneath, but that is for access speed, not for having a sorted object. An associative array is defined by its pairwise associations, not its physical order.)

You can sort on multiple criteria by defining an appropriate comparison function and applying it to the multimap. When firsts equal, the comparison function then sorts on another value (of your choice, given that the comparison function is customized to your liking...)

:-)
At the exam today I did everything except... yep... you've guessed right. Except that last thing with the two sorting keys.

Instead of clients with phones, I had to deal with items having prices (pretty much the same deal though). I had to sort items based on their type (specified inside a "code" ala phone number with a group) and sort each type alphabetically (i.e. by name).

As I said, the sorting function appears to have access only to the two keys, but not to the two values. Because multimaps can have the same key used for more than one value, there's no way with that function to target exactly the two values in question.

Now that I think about it, I could have used a nested multimap, i.e. have a multimap with the type as a key, and as a value - another multimap representing all items of this type with their names as keys. Too late now though.

Besides, as I expected, I didn't had enough time to copy my draft to my original paper. Not completely anyway. I left out the main() function.... hopefully the comitee will look at the draft as well. That's exactly why exams on paper suck big time. You can't simply copy&paste, or at least delete.

Ohhh... ok, now that I got that out of my system (I had to say all of the above somewhere), as far as the sorting in structures goes - I believe lists are designed to be unsorted, correct? I guess multimap was simply designed with this in mind, whereas lists were not. There should be something for everyone anyway.
Last edited on
I'm sure you did fine. Tests like that are always a pain.

There are two types of STL container: ordered, or sequence, containers, and associative containers.

A list is a sequence container --meaning that its elements are maintained in a specific order (which is wherever the user put them). The user accesses elements by index.

A map is an associative container --meaning that its elements may be reordered according to the container's pleasure. The user accesses the elements by name (or key).

:-)
Topic archived. No new replies allowed.