From: lindahlb on
#include <iostream>
using namespace std;

struct Ignore_Stream
{
#if 1
template<typename T>
Ignore_Stream operator<<(T) const;
#else
template<typename Char, typename Traits>
Ignore_Stream operator<<(basic_ostream<Char,Traits> &
(*)(basic_ostream<Char,Traits> &)) const;
#endif
};

int main(int argc, char * argv[])
{
Ignore_Stream() << endl;
return 0;
}

For both definitions, g++ complains about the above:
error: no match for 'operator<<' in 'Ignore_Stream() << std::endl'

Why? Is this a non-conformance problem, or is this behavior expected?
And how can I get the above to eat std::endl?

It should work, considering basic_ostream gets it to work (gcc STL uses
a signature almost identical to the signature in the alternate
definition).

Thanks for any help!


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Ulrich Eckhardt on
lindahlb(a)hotmail.com wrote:
> struct Ignore_Stream
> {
> #if 1
> template<typename T>
> Ignore_Stream operator<<(T) const;
> #else
> template<typename Char, typename Traits>
> Ignore_Stream operator<<(basic_ostream<Char,Traits> &
> (*)(basic_ostream<Char,Traits> &)) const;
> #endif
> };
>
> int main(int argc, char * argv[])
> {
> Ignore_Stream() << endl;
> return 0;
> }
>
> For both definitions, g++ complains about the above:
> error: no match for 'operator<<' in 'Ignore_Stream() << std::endl'
>
> Why?

Simple: 'endl' is an overloaded function (or is it a function template?),
and the compiler just can't decide on which overload to take.

I found in similar implementations that, in addition to the generic
inserter, I needed two more:
ostream& (*)(ostream&)
basic_ios& (*)(basic_ios&)

Though I'm having a hard time remembering what I needed the second one
for...

> It should work, considering basic_ostream gets it to work (gcc STL uses
> a signature almost identical to the signature in the alternate
> definition).

<historic nitpick>
Ewww, just one thing: The STL is the old template lib from HP (now at
SGI's). Most of it was incorporated into the C++ standardlibrary and
remains there with the C API and the IOStreams library. Other than that,
STL has nothing to do with IOStreams.
</historic nitpick>

Uli


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Maeder on
lindahlb(a)hotmail.com writes:

> #include <iostream>

std::endl is declared in the header <ostream>, which is not
necessarily pulled in by <iostream>.


> using namespace std;
>
> struct Ignore_Stream
> {
> #if 1
> template<typename T>
> Ignore_Stream operator<<(T) const;
> #else
> template<typename Char, typename Traits>
> Ignore_Stream operator<<(basic_ostream<Char,Traits> &
> (*)(basic_ostream<Char,Traits> &)) const;
> #endif
> };
>
> int main(int argc, char * argv[])
> {
> Ignore_Stream() << endl;
> return 0;
> }
>
> For both definitions, g++ complains about the above:
> error: no match for 'operator<<' in 'Ignore_Stream() << std::endl'
>
> Why? Is this a non-conformance problem, or is this behavior expected?
> And how can I get the above to eat std::endl?

The problem is that std::endl is a function template, with two
typename parameters like the second version of the operator<< member
template in your code above.

When we write

std::cout << std::endl;

, std::endl is specialized so as to fit the appropriate overload of
operator<< for std::cout, i.e. for Char==char and
Traits==std::char_traits<char>.


When you write

Ignore_Stream() << endl;

, however, the compiler doesn't know which character type you want
std::endl and operator<< to be specialized for.


If Ignore_Stream commits itself to a character type, e.g.:

struct Ignore_Stream
{
Ignore_Stream
operator<<(std::basic_ostream<char,std::char_traits<char> > &
(*)(std::basic_ostream<char,std::char_traits<char> > &));
};

, the statement

Ignore_Stream() << endl;

will be accepted.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alberto Ganesh Barbati on
lindahlb(a)hotmail.com ha scritto:
> #include <iostream>
> using namespace std;
>
> struct Ignore_Stream
> {
> <snip>
> template<typename Char, typename Traits>
> Ignore_Stream operator<<(basic_ostream<Char,Traits> &
> (*)(basic_ostream<Char,Traits> &)) const;
> <snip>
> };
>
> <snip>
>
> It should work, considering basic_ostream gets it to work (gcc STL uses
> a signature almost identical to the signature in the alternate
> definition).

In addition to what other posters have already correctly said, I would
like to notice that the signature you think it's "almost" identical is
in fact completely different! Compare the signature in your example
above with this one:

template <class charT, class traits = char_traits<charT> >
class basic_ostream : ...
{
//...
basic_ostream<charT,traits>& operator<<
(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
//...
};

Do you spot the difference? Yours is a member template, while ostream's
is not: it's a regular member (of a class template). That means the
template parameters in ostream's operator<< are not deduced: they *must*
match the object's char and traits. In the case of std::endl, which is a
function template, this fact allows the compiler to select one (and only
one) specialization of the std::endl.

In your case, the compiler needs to deduce the parameters and can't
because there are (potentially) infinite specializations of std::endl
that matches your signature.

Regards,

Ganesh

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bo Møller on
I am sure you want to do more advanced things than the given example.
> int main(int argc, char * argv[])
> {
> Ignore_Stream() << endl;
> return 0;
> }

But why do you want to make an Ignore_Stream?

If the purpose is to have a stream which discards all the data, then
maybe it would be a good idear to use a real stream, and supply it
with a NULL-buffer.

int main()
{
std::ostream ignoreStream(NULL);
ignoreStream << "This will be discarded" << std::endl;
}

By using a real ostream you get all << operators for free. In
addition you KNOW that it will behave like a ostream in EVERY aspect.

Maybe the thread "DebugLog. Bad design or.." from the begining of
august can give you some idears.

--
Bo M?ller

Hobby-Programmer



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 |  Next  |  Last
Pages: 1 2 3 4
Prev: Why is VC++ STL so slow?
Next: const and ABCs