compilation error using ofstream

A

aaragon

Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:

// main()
....
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
....

main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

Thank you all!

 
V

Victor Bazarov

aaragon said:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:

// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...

main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

I don't see any "Domain.h" or types called 'Domain' in your code.

V
 
A

aaragon

aaragon said:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

I don't see any "Domain.h" or types called 'Domain' in your code.

V

Well, I overloaded operator<< to produce the output of a class that I
designed. But shouldn't the compiler deduct this from the type being
passed to operator<<???? Why is it the call ambiguous????
 
M

martyw

aaragon said:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:

// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...

main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

Thank you all!

a minimal version of your program compiles and creates a file contianing
'hello ' after running:

#include <fstream>

int main()
{
std::eek:fstream fout;
fout.open("hello.out");
fout<<"hello ";
fout.close();
return 0;
}

did you include the first line in your code?
 
K

Kai-Uwe Bux

aaragon said:
aaragon said:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

I don't see any "Domain.h" or types called 'Domain' in your code.

V

Well, I overloaded operator<< to produce the output of a class that I
designed. But shouldn't the compiler deduct this from the type being
passed to operator<<???? Why is it the call ambiguous????

How are we supposed to know? Please, post a _complete_ (but minimal) program
that exhibits the problem (see the FAQ on how-to-post).


Best

Kai-Uwe Bux
 
J

Jim Langston

aaragon said:
aaragon said:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

I don't see any "Domain.h" or types called 'Domain' in your code.

V

Well, I overloaded operator<< to produce the output of a class that I
designed. But shouldn't the compiler deduct this from the type being
passed to operator<<???? Why is it the call ambiguous????

Does Domain perhaps accept a char* as a constructor?
 
A

aaragon

aaragon wrote:
Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1
I don't see any "Domain.h" or types called 'Domain' in your code.
V
Well, I overloaded operator<< to produce the output of a class that I
designed. But shouldn't the compiler deduct this from the type being
passed to operator<<???? Why is it the call ambiguous????

Does Domain perhaps accept a char* as a constructor?

Yes it does!!! The domain class can be created with a char* that I
pass (the name of a file). Why is this happening then?
 
J

Jim Langston

aaragon said:
aaragon wrote:
Hello, does anyone have a clue about this error? and how to solve
it?
It seems to be trivial to me, but not for the compiler. I'm using
g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char,
_Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*)
[with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1
I don't see any "Domain.h" or types called 'Domain' in your code.
Well, I overloaded operator<< to produce the output of a class that I
designed. But shouldn't the compiler deduct this from the type being
passed to operator<<???? Why is it the call ambiguous????

Does Domain perhaps accept a char* as a constructor?

Yes it does!!! The domain class can be created with a char* that I
pass (the name of a file). Why is this happening then?

I'm not actually positive, because I can't reproduce it in test, but what it
seems is that the compiler sees you are sending a char* to an ofstream. It
looks at sees that you have a Domain constructor that accepts a char* and
has an output to an ofstream. I wouldn't think that the compiler would pick
that, but it depends on how Domain is set up. Can you post the appropriate
Domain class? At least anything having to do with the constructor and any
operator<< overrides and such.
 
J

James Kanze

Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

Apparently, you have defined function operator<<( ofstream&,
....), and Domain has a constructor which can be called with a
char const*. So the first argument of this function is an exact
match, and thus a better than the operator<<( ostream&, char
const*). The second argument, of course, is a better match for
the first function, so the call is ambiguous.

The obvious question is: why on earth would you define an
operator<< which takes an ofstream, rather than an ostream? If
you define the operator to take an ostream, then both functions
are equally good matches for the first argument, and the fact
that the char const* is a better match for the second means that
it will be chosen.
 
J

Joe Greer

Yes it does!!! The domain class can be created with a char* that I
pass (the name of a file). Why is this happening then?

A literal string like "Hello" is actually of type char const [6] and
requires an implicit cast to become a char const * for operator<<.
Unless you have your domain class constructor marked as explicit, the compiler
sees that as an additional way to convert your literal string into something
that operator<< knows how to handle. In other words, both

fout << static_cast<char *>("Hello");

and

fout << static_cast<Domain>("Hello");

are viable choices and the compiler doesn't know which one you want. Of course,
you would never write like the above, but I was trying to represent it in a way
that would show that to the compiler, both are equally viable, though to your
eyes and mine, the first is the obvious choice. To tell the compiler that the
first is the obvious choice, you should mark the constructor for the Domain as explicit.

Interestingly enough VC8 doesn't see an ambiguity, though it should.

joe
 
J

Joe Greer

Interestingly enough VC8 doesn't see an ambiguity, though it should.

Ah, James Kanz reply explains why my quickly cobbled together test didn't
show the ambiguity in VC8. I overloaded for ostream instead of fostream
and had a better match. (You have to love a language which takes this kind
of analysis to figure out what's going on, don't you?) In any case, I think
that if you mark your constructor as explicit, you will solve your problem and
possibly prevent others like this.

joe
 
A

aaragon

Hello, does anyone have a clue about this error? and how to solve it?
It seems to be trivial to me, but not for the compiler. I'm using g++
4.2 on an Ubuntu Linux system:
// main()
...
std::eek:fstream fout;
fout.open("hello.out");
fout<<setfill('-')<<setw(20)<<"-"<<setfill(' ')<<endl;
fout<<"hello "; // this is line 139
...
main.cxx:89: instantiated from here
main.cxx:139: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/
ostream.tcc:735: note: candidate 1: std::basic_ostream<char, _Traits>&
std::eek:perator<<(std::basic_ostream<char, _Traits>&, const char*) [with
_Traits = std::char_traits<char>]
Domain.h:507: note: candidate 2: o& operator<<(o&, const Domain&)
[with o = std::eek:fstream]
make: *** [main.o] Error 1

Apparently, you have defined function operator<<( ofstream&,
...), and Domain has a constructor which can be called with a
char const*. So the first argument of this function is an exact
match, and thus a better than the operator<<( ostream&, char
const*). The second argument, of course, is a better match for
the first function, so the call is ambiguous.

The obvious question is: why on earth would you define an
operator<< which takes an ofstream, rather than an ostream? If
you define the operator to take an ostream, then both functions
are equally good matches for the first argument, and the fact
that the char const* is a better match for the second means that
it will be chosen.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Well, I actually defined operator<< as a template function that could
take an ostream or a ofstream. Thus, I can output to screen using cout
and output to a file using an ofstream with the same code. I will
declare the constructor as explicit. Thank you guys for all your
answers! They're very appreciated.
 
P

Pete Becker

Well, I actually defined operator<< as a template function that could
take an ostream or a ofstream. Thus, I can output to screen using cout
and output to a file using an ofstream with the same code. I will
declare the constructor as explicit. Thank you guys for all your
answers! They're very appreciated.

Making the constructor explicit treats the symptom, but not the
problem. To be able to write to an ofstream as well as to cout, write
an inserter that takes an ostream&. That's what all the standard
inserters do (well, actually, they're templates, and they take an
appropriate instantiation of basic_ostream).
 
A

aaragon

Making the constructor explicit treats the symptom, but not the
problem. To be able to write to an ofstream as well as to cout, write
an inserter that takes an ostream&. That's what all the standard
inserters do (well, actually, they're templates, and they take an
appropriate instantiation of basic_ostream).

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Could you expand on the inserter subject? or give me a link where I
can read about it? Thank you.
 
J

James Kanze

Ah, James Kanz reply explains why my quickly cobbled together
test didn't show the ambiguity in VC8. I overloaded for
ostream instead of fostream and had a better match. (You have
to love a language which takes this kind of analysis to figure
out what's going on, don't you?)

There are several places where you need this kind of analysis if
you really want to understand what's going on; function overload
resolution is one of them. On the other hand, in the case of
function overload resolution, it normally "does what you'd
expect", at least in well written code. In this case, the rule
is simple---overloaded << operators should *always* take an
std::eek:stream&, and not an std::eek:fstream&. Independant of the
overload ambiguities:
someFile << "label: " << objectOfMyType ;
will not work otherwise, since the << for char const* will
return an ostream&, and not an ofstream&.
In any case, I think that if you mark your constructor as
explicit, you will solve your problem and possibly prevent
others like this.

It's quite possible that it would be a good idea to mark the
constructor as explicit---IMHO, that should be the default, and
implicit conversions are often a source of ambiguities and other
problems. But in this case, there is an absolute rule: the <<
should *always* take an ostream& as its first argument, never a
class derived from ostream.
 
J

James Kanze

Could you expand on the inserter subject? or give me a link
where I can read about it? Thank you.

There's not much to expand. As Pete said, an inserter (an
operator<<) should always take an instantiation of basic_ostream
as its first parameter (unless it is designed to insert into
streams unrelated to basic_ostream). Unless you really want to
be able to insert into any type of basic_ostream (a lot of work,
generally for nothing), just use std::eek:stream&.

All of the other output streams (ofstream, ostringstream, etc.)
and the bi-directional streams (iostream, fstream, stringstream)
derive from ostream, so an << taking an ostream will output
correctly to any of them. All of the standard << operators
return an ostream, so if you write something like:

out << "label: " << objectOfMyType ;

it will only work if objectOfMyType has an << defined that works
for ostream. The only time you write an operator<< which
doesn't take an ostream& as its first parameter (and return an
ostream&) is when you don't want it to work in cases like the
above; that would only be the case when the standard <<
operators are not appropriate for the stream. (I have an
oxdrstream, for example, where this is the case: it outputs data
in the binary xdr format, and not as text.)

A priori, the iostream's chapter in Josuttis covers the issue.
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top