|
Prev: Why is VC++ STL so slow?
Next: const and ABCs
From: lindahlb on 30 Sep 2006 03:38 #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 30 Sep 2006 10:54 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 30 Sep 2006 10:55 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 1 Oct 2006 05:57 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 2 Oct 2006 12:36
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! ] |