# Vecotor of Pairs

A

#### arnuld

I know the line which causes the error but unable to find out the why. The
line in STEP 4, "std:stream_iterator<stint>( std::cout, "\n" ), is the
source of error:

/* C++ Primer - 4/e
*
* CHAPTER 10 - Associative Containers
*
* EXERCISE - 10.1
* Write a program to read a sequence of strings and ints, storing
* each into a pair. Store the pairs into a Vector.
*
*/

/* We will solve this problem in 4 steps

1.) Define all the variables we need.
2.) Get input and store that into the pair.
3.) store the respective pair into the Vector.
4.) print the vector ( to see if the program really worked or not).

*/

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <iterator>

int main()
{
/* STEP 1
each pair will represent a string as first member connected to an int
as second memeber.
*/
typedef std:air<std::string, int> stint;
std::vector<stint> vec_stint;

/* STEP 2 & 3 */
std::string ele1;
int ele2;

std::cout << "Please enter a word at 1st input and
a number at 2nd iput and so on"
<< std::endl;

while( std::cin >> ele1 >> ele2 )
{
stint current_stint = make_pair( ele1, ele2 );
vec_stint.push_back(current_stint );
}

/* STEP 4 */
std::copy( vec_stint.begin(), vec_stint.end(),
std:stream_iterator<stint>( std::cout, "\n" ));

return 0;

}

========= OUTPUT ===============

[arnuld@gnu programs]\$ g++ -ansi -pedantic -Wall -Wextra 10.01.cpp
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stream_iterator.h:
In member function â€˜std:stream_iterator<_Tp, _CharT, _Traits>&
std:stream_iterator<_Tp, _CharT, _Traits>:perator=(const _Tp&) [with
_Tp = std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int>, _CharT = char, _Traits =
std::char_traits<char>]â€™:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stl_algobase.h:283:
instantiated from â€˜static _OI std::__copy<_BoolType,
std::random_access_iterator_tag>::copy(_II, _II, _OI) [with _II =
std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int>*, _OI =
std:stream_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>, char,
std::char_traits<char> >, bool _BoolType = false]â€™
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stl_algobase.h:315:
instantiated from â€˜_OI std::__copy_aux(_II, _II, _OI) [with _II =
std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int>*, _OI =
std:stream_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>, char,
std::char_traits<char> >]â€™
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stl_algobase.h:349:
instantiated from â€˜static _OI std::__copy_normal<true,
false>::__copy_n(_II, _II, _OI) [with _II =
__gnu_cxx::__normal_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>*,
std::vector<std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int>,
std::allocator<std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int> > > >, _OI =
std:stream_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>, char,
std::char_traits<char> >]â€™
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stl_algobase.h:401:
instantiated from â€˜_OutputIterator std::copy(_InputIterator,
_InputIterator, _OutputIterator) [with _InputIterator =
__gnu_cxx::__normal_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>*,
std::vector<std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int>,
std::allocator<std:air<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, int> > > >, _OutputIterator =
std:stream_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>, char,
std::char_traits<char> >]â€™ 10.01.cpp:51: instantiated from here
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.2.2/../../../../include/c++/4.2.2/bits/stream_iterator.h:196:
error: no match for â€˜operator<<â€™ in
â€˜*((std:stream_iterator<std:air<std::basic_string<char,
std::allocator<char> > said:
*)this)->std:stream_iterator<std:air<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, int>, char,
std::char_traits<char> >::_M_stream << __valueâ€™

K

#### Kai-Uwe Bux

arnuld said:
I know the line which causes the error but unable to find out the why. The
line in STEP 4, "std:stream_iterator<stint>( std::cout, "\n" ), is the
source of error:

/* C++ Primer - 4/e
*
* CHAPTER 10 - Associative Containers
*
* EXERCISE - 10.1
* Write a program to read a sequence of strings and ints, storing
* each into a pair. Store the pairs into a Vector.
*
*/

/* We will solve this problem in 4 steps

1.) Define all the variables we need.
2.) Get input and store that into the pair.
3.) store the respective pair into the Vector.
4.) print the vector ( to see if the program really worked or not).

*/

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <iterator>

int main()
{
/* STEP 1
each pair will represent a string as first member connected to an int
as second memeber.
*/
typedef std:air<std::string, int> stint;
std::vector<stint> vec_stint;

/* STEP 2 & 3 */
std::string ele1;
int ele2;

std::cout << "Please enter a word at 1st input and
a number at 2nd iput and so on"
<< std::endl;

while( std::cin >> ele1 >> ele2 )
{
stint current_stint = make_pair( ele1, ele2 );
vec_stint.push_back(current_stint );
}

/* STEP 4 */
std::copy( vec_stint.begin(), vec_stint.end(),
std:stream_iterator<stint>( std::cout, "\n" ));

return 0;

}

The problem is that std:air<> does not define operator<<. This is one of
the major shortcomings of standard containers: they don't have IO and you
cannot work around it since you are not allowed to add the necessary
overloads to namespace standard. Instead of providing a reasonable default,
the standard chose to not provide IO at all. I don't think the decision was
wise, but we have to live with it. It's very unlikely to change.

This is one of the very few instances where inheriting from standard
containers provides a viable solution. If you do:

struct stint : public std:air< std:.string, int > {
// some constructors

friend
std:stream & operator<< ( std:stream & str, stint const & value ) {
...
}
};

your code should compile (however, you would need to replace make_pair with
the correct constructor calls. You could also consider private inheritance
+ using directives (one can argue that that would be better).

Now, for a class like std:air, this sort of public inheritance saves you
almost no writing; but for classes like std::vector it can be a usefull
technique to create type-clones (as opposed to type-aliases obtained by
typedef).

Alternatively, you could define your own streams outside namespace standard.

Finally, you can write the IO without using operator<< on pairs.

Best

Kai-Uwe Bux

Z

#### Zara

I know the line which causes the error but unable to find out the why. The
line in STEP 4, "std:stream_iterator<stint>( std::cout, "\n" ), is the
source of error:
int main()
{
/* STEP 1
each pair will represent a string as first member connected to an int
as second memeber.
*/
typedef std:air<std::string, int> stint;
std::vector<stint> vec_stint;

/* STEP 2 & 3 */
std::string ele1;
int ele2;

std::cout << "Please enter a word at 1st input and
a number at 2nd iput and so on"
<< std::endl;

Take care! You have un unterminated string here. I suppose it comes
from copy/pasting, but you should have edited it.
while( std::cin >> ele1 >> ele2 )
{
stint current_stint = make_pair( ele1, ele2 );
vec_stint.push_back(current_stint );
}

/* STEP 4 */
std::copy( vec_stint.begin(), vec_stint.end(),
std:stream_iterator<stint>( std::cout, "\n" ));

You have neither declared nor defined the function:

std:stream& operator<<(std:stream& strm, const stint& data);
return 0;

}
<...>

Best regards,

Zara

A

#### arnuld

The problem is that std:air<> does not define operator<<. This is one
of the major shortcomings of standard containers: they don't have IO and
you cannot work around it since you are not allowed to add the necessary
overloads to namespace standard. Instead of providing a reasonable
default, the standard chose to not provide IO at all. I don't think the
decision was wise, but we have to live with it. It's very unlikely to
change.

....[SNIP]........
Now, for a class like std:air, this sort of public inheritance saves
you almost no writing; but for classes like std::vector it can be a
usefull technique to create type-clones (as opposed to type-aliases
obtained by typedef).

I did not know that IO is not defined even for Vectors

Alternatively, you could define your own streams outside namespace
standard.

that's a better idea, i guess.

Finally, you can write the IO without using operator<< on pairs.

that is best I think , so i changed my code to look like this:

std::string first = my_pair.first;
int second = my_pair.second;

std::cout << "1st Element: " << first << "\n"
<< "2nd Element: " << second << "\n";

and that compiles and runs

thanks a lot Bux

W

#### werasm

Take care! You have un unterminated string here. I suppose it comes
from copy/pasting, but you should have edited it.

Perhaps I'm blind, but I see no unterminated string anywhere. Care
to point out the line you're referring to please?

Werner

L

#### LR

Kai-Uwe Bux said:
The problem is that std:air<> does not define operator<<. This is one of
the major shortcomings of standard containers: they don't have IO and you
cannot work around it since you are not allowed to add the necessary
overloads to namespace standard. Instead of providing a reasonable default,
the standard chose to not provide IO at all. I don't think the decision was
wise, but we have to live with it. It's very unlikely to change.

This is one of the very few instances where inheriting from standard
containers provides a viable solution. If you do:

struct stint : public std:air< std:.string, int > {
// some constructors

friend
std:stream & operator<< ( std:stream & str, stint const & value ) {
...
}
};

your code should compile (however, you would need to replace make_pair with
the correct constructor calls. You could also consider private inheritance
+ using directives (one can argue that that would be better).

Now, for a class like std:air, this sort of public inheritance saves you
almost no writing; but for classes like std::vector it can be a usefull
technique to create type-clones (as opposed to type-aliases obtained by
typedef).

Alternatively, you could define your own streams outside namespace standard.

Finally, you can write the IO without using operator<< on pairs.

I'm having some trouble understanding what you mean.

Would this snippet be legal?

#include <iostream>
class MyClass1 {};
class MyClass2 {};

std:stream &operator<<(std:stream &o, const MyClass1 &m) {
o << "MyClass1";
return o;
}

std:stream &operator<<(std:stream &o, const MyClass2 &m) {
o << "MyClass2";
return o;
}

std:stream &operator<<(std:stream &o,
const std:air<MyClass1,MyClass2> &pr) {
o << "(" << pr.first << "," << pr.second << ")";
return o;
}

int main() {
MyClass1 m1;
MyClass2 m2;

std::cout << std::make_pair(m1,m2) << std::endl;
}

If it is legal, what is the advantage of the struct you show above?

TIA

LR

K

#### Kai-Uwe Bux

LR said:
I'm having some trouble understanding what you mean.

Would this snippet be legal?

#include <iostream>
class MyClass1 {};
class MyClass2 {};

std:stream &operator<<(std:stream &o, const MyClass1 &m) {
o << "MyClass1";
return o;
}

std:stream &operator<<(std:stream &o, const MyClass2 &m) {
o << "MyClass2";
return o;
}

std:stream &operator<<(std:stream &o,
const std:air<MyClass1,MyClass2> &pr) {
o << "(" << pr.first << "," << pr.second << ")";
return o;
}

int main() {
MyClass1 m1;
MyClass2 m2;

std::cout << std::make_pair(m1,m2) << std::endl;
}

If it is legal, what is the advantage of the struct you show above?

The code is legal. You have defined operator<< in the namespace where you
use it. Unfortunately, that does not imply that you solved the problem of
IO for the type std:air<MyClass1,MyClass2>. Consider the following slight
variation of main:

int main() {
MyClass1 m1;
MyClass2 m2;
*std:stream_iterator< std:air<MyClass1,MyClass2> >( std::cout, "" )
<< std::make_pair(m1,m2);
std::cout << std::endl;
}

All of a sudden you get a strange error. The reason is that ostream_iterator
issues a call of operator<< for std:air<MyClass1,MyClass2> _from within_
the namespace std. In such a context, the operator<< you provided will not
be found. The only way to ensure that it is found, is to put the IO
operators into the same namespace as the pair-template. But that is not
allowed. It is at this point where type-clones enter the picture.

Best

Kai-Uwe Bux

A

#### arnuld

The problem is that std:air<> does not define operator<<. This is one
of the major shortcomings of standard containers: they don't have IO and
you cannot work around it since you are not allowed to add the necessary
overloads to namespace standard. Instead of providing a reasonable
default, the standard chose to not provide IO at all. I don't think the
decision was wise, but we have to live with it. It's very unlikely to
change.
...[SNIP].....

Finally, you can write the IO without using operator<< on pairs.

I came up with this code:

int main()
{
/* STEP 1
each pair will represent a string as first member connected to an
int as second memeber.
*/
typedef std:air<std::string, int> stint;
std::vector<stint> vec_stint;

/* STEP 2 & 3 */
std::string ele1;
int ele2;
std::cout << " Please enter a word at 1st input\n &
a number at 2nd iput and so on\n
...... Thanks ......" << std::endl;
while( std::cin >> ele1 >> ele2 )
{
stint current_stint = make_pair( ele1, ele2 );
vec_stint.push_back(current_stint );
}

/* STEP 4 */
typedef std::vector<stint>::const_iterator pair_iter;
for( pair_iter iter = vec_stint.begin();
iter != vec_stint.end(); ++iter)
{
std::string first_element = (*iter).first;
int second_element = (*iter).second;

std::cout << "1st Element: " << first_element << "\n"
<< "2nd Element: " << second_element << std::endl;
}

return 0;

}

=============== OUTPUT ==================

/home/arnuld/programs \$ ./a.out
Please enter a word at 1st input
& a number at 2nd iput and so on
...... Thanks ......
arnuld
007
Father
009
Bazarov
000
1st Element: arnuld
2nd Element: 7
1st Element: Father
2nd Element: 9
1st Element: Bazarov
2nd Element: 0
/home/arnuld/programs \$ ./a.out
Please enter a word at 1st input
& a number at 2nd iput and so on
...... Thanks ......
9
bazarov
/home/arnuld/programs \$

have a look at the output. it runs fine when 1st input is string and 2nd
is int. but when I reverse the input types then program runs fine but just
"quits itself automatically" without giving any run time error. Her
eis my explanation: "std::cin >> ele1 >> ele2" runs like this:

(std::cin >> ele1) >> ele2
std::cin >> ele2

1st step is fine because any input will be taken as a string. At 2nd step
the program crashes because C++ can not convert a string into an integer
but why I did not get any run-time error ? Program just quits silently
and beautifully. Why so ?

D

#### David Harmon

On Thu, 22 Nov 2007 00:41:04 -0800 (PST) in comp.lang.c++, werasm
Perhaps I'm blind, but I see no unterminated string anywhere. Care
to point out the line you're referring to please?

These lines:

std::cout << "Please enter a word at 1st input and
a number at 2nd iput and so on"
<< std::endl;

Should have been written as:

std::cout << "Please enter a word at 1st input and "
"a number at 2nd iput and so on\n";

## Ask a Question

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

### Members online

No members online now.