non-template ostream_iterator?

Hi @, does anybody know why the ostream_iterator class has been mad a template if a template just for the assignment operator would have been sufficient? I.e., why does it say: template<class T> ostream_iterator { ... public: ostream_iterator& operator=(T const&); ... }; instead of ostream_iterator { ... public: template<class T> ostream_iterator& operator=(T const&); ... }; or possibly: template<class os=std::ostream> ostream_iterator { ... public: typedef typename os::char_type char_type; typedef typename os::traits_type traits_type; typedef os ostream_type; template<class T> ostream_iterator& operator=(T const&); ... }; In my compiler version (g++ 3.0 and g++ 3.4) the type T is used nowhere else. As a consequence I have to specify myContainer v; copy(v.begin(), v.end(), ostream_iterator<myContainer::value_type>(cout, "\n")); while it just could be: copy(v.begin(), v.end(), ostream_iterator(cout, "\n")); or copy(v.begin(), v.end(), ostream_iterator<>(cout, "\n")); The answer is obvious for istream_iterators: They provide their input values through the operator*() and have, giving the fact that it does not take any argument, no way to deduce the required return type, so it needs to be specified explicitly. That's different for ostream_iterators. They get their output values as arguments and are perfectly capable of deducing their type, so requiring it as an explicit template argument seems to be an unnecessary over-specification. One could argue, that the template argument adds to type safety, but that sound rather weak to me, especially if standard streams are involved. After all, std::cout and std::cerr are both global, so there's nothing at all to prevent me from printing to them from anywhere else in my application, even from a call implicitly made by function used in the expression above; let alone threads or other operating system processes. So, it seems to me, that the template argument does not provide any additional value but only makes the expression above unnecessary complicate. Am I missing something? Thanks, Andreas

On Nov 21, 2007 10:07 PM, Andreas Harnack <ah.boost.04@justmail.de> wrote:
So, it seems to me, that the template argument does not provide any additional value but only makes the expression above unnecessary complicate. Am I missing something?
Disclaimer: I am not part of the C++ Standards Committe. All that follow are based on my interpretations of the situation. Remember that some compilers (legacy I would like to think) do not support template member functions. So for something in the standard library to rely on a feature that not all compilers will support would be careless. Another is the issue of conversion, and enforcement of concepts on the type T. When you want to ensure that T is default constructable and assignable, and you want to force conversions of objects passed to your function to T, you'd have code that looks like: template <typename TReal> struct polymorphic_conversion_forcer { template <typename TDeduced> void function(TDeduced const & t) { TReal r = t; // TReal should be default constructable and assignable, and TDeduced should be convertible to TReal }; }; I hope this contributes to why ostream_iterator needs the T defined as a class template instead of as a deduced member function. -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

Dean Michael Berris wrote:
Another is the issue of conversion, and enforcement of concepts on the type T. When you want to ensure that T is default constructable and assignable, and you want to force conversions of objects passed to your function to T, you'd have code that looks like:
template <typename TReal> struct polymorphic_conversion_forcer {
template <typename TDeduced> void function(TDeduced const & t) { TReal r = t; // TReal should be default constructable and assignable, and TDeduced should be convertible to TReal };
};
Apart from the historical reason, ostream_iterator seems to fall into anti-pattern: one name, two functionality. The enforcement part could be delegated to another output iterator adaptor. My current solution is something like this: copy(stream_read<char>(std::in), converter<std::string>() |= stream_writer(std::cout)); Regards, -- Shunsuke Sogame
participants (3)
-
Andreas Harnack
-
Dean Michael Berris
-
shunsuke