Why isn't the operator<< found?

L

lutorm

Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

#include <fstream>
#include <vector>
#include <iterator>

using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),
(istream_iterator<float_pair> ()));
}

This used to work under my old compiler (KCC) but GCC 4.0 says it can't
find the operator<< (I think...) The full error message is below.
However, the operator works because when I try to read an individual
pair it works. Is there some magic that needs to be performed for the
istream_iterator to find the operator<<?

Thanks,

/Patrik Jonsson


[patrik@governator src]$ g++ optest.cc
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/bits/stream_iterator.h:
In member function 'void std::istream_iterator<_Tp, _CharT, _Traits,
_Dist>::_M_read() [with _Tp = float_pair, _CharT = char, _Traits =
std::char_traits<char>, _Dist = ptrdiff_t]':
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/bits/stream_iterator.h:68:
instantiated from 'std::istream_iterator<_Tp, _CharT, _Traits,
_Dist>::istream_iterator(std::basic_istream<_CharT, _Traits>&) [with
_Tp = float_pair, _CharT = char, _Traits = std::char_traits<char>,
_Dist = ptrdiff_t]'
optest.cc:24: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/bits/stream_iterator.h:119:
error: no match for 'operator>>' in
'*((std::istream_iterator<float_pair, char, std::char_traits<char>,
ptrdiff_t>*)this)->std::istream_iterator<float_pair, char,
std::char_traits<char>, ptrdiff_t>::_M_stream >>
((std::istream_iterator<float_pair, char, std::char_traits<char>,
ptrdiff_t>*)this)->std::istream_iterator<float_pair, char,
std::char_traits<char>, ptrdiff_t>::_M_value'
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:131:
note: candidates are: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT,
_Traits>::eek:perator>>(std::basic_istream<_CharT, _Traits>&
(*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits
= std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:134:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(std::basic_ios<_CharT,
_Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char,
_Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:137:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(std::ios_base&
(*)(std::ios_base&)) [with _CharT = char, _Traits =
std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:169:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(bool&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:172:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(short int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:175:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(short unsigned int&)
[with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:178:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(int&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:181:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(unsigned int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:184:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long int&) [with _CharT
= char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:187:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long unsigned int&)
[with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:191:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long long int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:194:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long long unsigned
int&) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:198:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(float&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:201:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(double&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:204:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long double&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:207:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(void*&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:230:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT,
_Traits>::eek:perator>>(std::basic_streambuf<_CharT, _Traits>*) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:688:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, unsigned char&)
[with _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:693:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, signed char&) [with
_Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:729:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, unsigned char*)
[with _Traits = std::char_traits<char>]
/usr/lib/gcc/x86_64-redhat-linux/4.0.0/../../../../include/c++/4.0.0/istream:734:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, signed char*) [with
_Traits = std::char_traits<char>]
 
S

Steven T. Hatton

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

#include <fstream>
#include <vector>
#include <iterator> ....
I don't know if you copied the code incorrectly, or the code you intended to
post had a parenthesis in the wrong place. Note that I used both GCC 3.3.5
and GCC 4.0.1. You may want to get the latest minor version.

$cat main.cpp
#include <fstream>
#include <vector>
#include <iterator>
#include <istream>

using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),istream_iterator<float_pair> ());
}


$gcc --version
gcc (GCC) 4.0.1
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -otest main.cpp
$
 
I

Ian

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

#include <fstream>
#include <vector>
#include <iterator>

using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),
(istream_iterator<float_pair> ()));
}
It's not << (must be all the template <) that can't be found, this
should compile OK.

Ian
 
M

Manfred

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

#include <fstream>
#include <vector>
#include <iterator>

using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)

Shouldn't this line be:
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),
(istream_iterator<float_pair> ()));
}

This used to work under my old compiler (KCC) but GCC 4.0 says it can't
find the operator<< (I think...) The full error message is below.
However, the operator works because when I try to read an individual
pair it works. Is there some magic that needs to be performed for the
istream_iterator to find the operator<<?

You haven't defined operator<< (see above).

Manfred
 
M

Maxim Yegorushkin

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:
using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),
(istream_iterator<float_pair> ()));
}

This used to work under my old compiler (KCC) but GCC 4.0 says it can't
find the operator<< (I think...) The full error message is below.
However, the operator works because when I try to read an individual
pair it works. Is there some magic that needs to be performed for the
istream_iterator to find the operator<<?

The problem is that pair is declared in namespace std and the code for
istream_iterator as well the code for vector also are in namespace std.
istream_iterator uses operator>> for extraction. When it does this it
first searches for a most inner scope containing operator>>. The scope
happens to be namespace std, and none of the overloaded operator>>
declared there takes a pair. Second, it does an argument dependent name
lookup for operator>>. Since both of its arguments come from namespace
std the lookup never finds your global operator>>.

To workaround you may screw the standard and declare your operator>> in
namespace std. Be aware that this might lead to hard to track bugs if
some other smart guy does the same thing in one of the other
translation units your binary is comprised of.

The most portable solution is to use your own type instead of std::pair
and overload operator>> for it.
 
L

lutorm

Steven said:
I don't know if you copied the code incorrectly, or the code you intended to
post had a parenthesis in the wrong place. Note that I used both GCC 3.3.5
and GCC 4.0.1. You may want to get the latest minor version.

No, it was copied correctly. The extra parentheses around one of the
istream_iterators are necessary because otherwise you don't create a
vector, you declare a function. Or at least so Item 6 (C++'s most
vexing parse) of Scott Myers' "Effective STL" says.

But after browsing a little more, I found the solution: The operator
apparently has to be declared in namespace std. I'm not sure why,
because I thought that lookup included the namespace of the caller, but
clearly I'm wrong. If anyone can offer an explanation of this, I'd be
all ears! :)

/Patrik
 
S

Steven T. Hatton

lutorm said:
No, it was copied correctly. The extra parentheses around one of the
istream_iterators are necessary because otherwise you don't create a
vector, you declare a function. Or at least so Item 6 (C++'s most
vexing parse) of Scott Myers' "Effective STL" says.

Sorry. I realized that's what was going on after I sent the message. For
some strange reason only one of the parentheses was copied into the Emacs
buffer. (there's something broken in my beta version of KNode). When the
code didn't compile, I just removed the one parenthesis.
But after browsing a little more, I found the solution: The operator
apparently has to be declared in namespace std. I'm not sure why,
because I thought that lookup included the namespace of the caller, but
clearly I'm wrong. If anyone can offer an explanation of this, I'd be
all ears! :)

/Patrik

Can you provide the source where you found someone saying the operator needs
to be declared in namespace std, or are you talking about Maxim's post
here?
 
S

Steven T. Hatton

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

What about this kludge?
struct float_pair: public pair<double, double>{};
 
M

Maxim Yegorushkin

Steven said:
What about this kludge?
struct float_pair: public pair<double, double>{};

You lose pair's constructors - all the functions it provides.
 
I

Ian

Maxim said:
The problem is that pair is declared in namespace std and the code for
istream_iterator as well the code for vector also are in namespace std.
istream_iterator uses operator>> for extraction. When it does this it
first searches for a most inner scope containing operator>>. The scope
happens to be namespace std, and none of the overloaded operator>>
declared there takes a pair. Second, it does an argument dependent name
lookup for operator>>. Since both of its arguments come from namespace
std the lookup never finds your global operator>>.
Are you sure? Even when all the types are fully qualified as in this
example?

Ian
 
M

Maxim Yegorushkin

[]
Are you sure?

Yes, I am.
Even when all the types are fully qualified as in this example?

file >> p; // this works

The call here works because it finds operator>> using ordinary lookup
because this is no template code. The set of viable functions for call
is comprised of the global operator>> and those found by ADL. The
latter set is empty.

istream_iterator<float_pair> does not work because it's a template, so
it searches for an operator>> in the second phase of name lookup using
ADL only, because the call is argument dependent. Since the operator>>
is not in the same namespace as any of its arguments, it can never be
found by ADL.
 
L

lutorm

Maxim said:
You lose pair's constructors - all the functions it provides.

Even more significantly for me, vector<float_pair> is then not
convertible to vector<pair<float, float> >, which I'm compelled to pass
later on.
 
S

Steven T. Hatton

lutorm said:
Hi everyone,
I'm trying to use istream_iterators to read a file consisting of pairs
of numbers. To do this, I wrote the following:

#include <fstream>
#include <vector>
#include <iterator>

using namespace std;

typedef std::pair<double, double> float_pair;

std::istream& operator>> (std::istream& s,
std::pair<double, double>& p)
{
s >> p.first;
s >> p.second;
return s;
}

main(){
ifstream file ("filename");

float_pair p;
file >> p; // this works

std::vector<float_pair> positions // but this doesn't
(istream_iterator<float_pair> (file),
(istream_iterator<float_pair> ()));
}

This used to work under my old compiler (KCC) but GCC 4.0 says it can't
find the operator<< (I think...) The full error message is below.
However, the operator works because when I try to read an individual
pair it works. Is there some magic that needs to be performed for the
istream_iterator to find the operator<<?

Thanks,

/Patrik Jonsson

I haven't been able to make anything work, but I've been trying to create a
wrapper similar to an I/O manipulator that would serve no other real
function in life other than to bring the namespace into scope. I wonder if
someone else can find a way to accomplish that.
 
M

Maxim Yegorushkin

lutorm said:
Even more significantly for me, vector<float_pair> is then not
convertible to vector<pair<float, float> >, which I'm compelled to pass
later on.

You can still make it convertible, though it makes you copy:

#include <vector>
#include <algorithm>

struct S
{
float a, b;
operator std::pair<float, float>() const { return std::make_pair(a,
b); }
};

int main()
{
using namespace std;
vector<S> p;
vector<pair<float, float> > q(p.begin(), p.end());
}
 

Ask a Question

Want to reply to this thread or ask your own 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.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top