[boost][lexical_cast] simple example doesn't work with vector<T>

Hi, Sorry trivial questions I'm sure. Why doesn't the lexical_cast work below? I think it meets the concept description. * Source is OutputStreamable, meaning that an operator<< is defined that takes a std::ostream or std::wostream object on the left hand side and an instance of the argument type on the right. * Target is InputStreamable, meaning that an operator>> is defined that takes a std::istream or std::wistream object on the left hand side and an instance of the result type on the right. * Target is CopyConstructible [20.1.3]. * Target is DefaultConstructible, meaning that it is possible to default-initialize an object of that type [8.5, 20.1.4].
play.cpp >>>>
#include <vector> #include <iostream> #include <algorithm> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include <sstream> using namespace std; using namespace boost; using namespace boost::filesystem; template<class T> ostream& operator<< (ostream& os, const vector<T>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } template<class T> string v2s(const vector<T>& v) { stringstream ss; copy(v.begin(), v.end(), ostream_iterator<T>(ss, ";")); return ss.str(); } int main(int argc, char* argv[]) { vector<string> v; v.push_back("hello"); v.push_back("world"); cout << v << endl; cout << v2s(v) << endl; cout << lexical_cast<string>(v) << endl; // XXX doesn't compile...XXX return 0; } Any help greatly appreciated. Andy

Andy Stevenson <andy.stevenson <at> uk.fujitsu.com> writes:
Why doesn't the lexical_cast work below?
Because your operator<< is not visible inside namespace boost. -- Alexander Nasonov

AMDG Scott McMurray wrote:
On Sun, Apr 6, 2008 at 5:15 PM, Andy Stevenson <andy.stevenson@uk.fujitsu.com> wrote:
Why doesn't the lexical_cast work below?
Your operator<<'s not in namespace std, so ADL cannot find it.
( I think that's it, anyways. )
Yes. It isn't legal to put it in namespace std, though. In Christ, Steven Watanabe

Just an addition: Explicit specialization of std templates is legal. So if you _exactly_ know vector types for which your <<-operator should work you can write: namespace std { template<> ostream& operator<< (ostream& os, const vector<MyTypeX>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } } By the way there was a big discussion about this on std list and I fluently read the upcoming Standard draft and saw that this paragraph changed. I not any longer sure if this will be allowed with the new standard. Best Regards, Ovanes On Mon, Apr 7, 2008 at 8:14 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Scott McMurray wrote:
On Sun, Apr 6, 2008 at 5:15 PM, Andy Stevenson <andy.stevenson@uk.fujitsu.com> wrote:
Why doesn't the lexical_cast work below?
Your operator<<'s not in namespace std, so ADL cannot find it.
( I think that's it, anyways. )
Yes. It isn't legal to put it in namespace std, though.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

AMDG Ovanes Markarian wrote:
Just an addition:
Explicit specialization of std templates is legal. So if you _exactly_ know vector types for which your <<-operator should work you can write:
namespace std { template<> ostream& operator<< (ostream& os, const vector<MyTypeX>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } }
By the way there was a big discussion about this on std list and I fluently read the upcoming Standard draft and saw that this paragraph changed. I not any longer sure if this will be allowed with the new standard.
There has to be template to specialize. The std library doesn't have an overload of operator<< that matches std vector. Specialization can't change that. In Christ, Steven Watanabe

All, Thanks to Steven Watanabe, Ovanes Markarian, Scott Murray, Alexander Nasonov who all responded to this. The suggestions were to put it into namespace std or boost, both seem to work by the way. However what is actually right here? Extending std seems distinctly non-std ! Andy -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Steven Watanabe Sent: 07 April 2008 20:04 To: boost-users@lists.boost.org Subject: Re: [Boost-users] [boost][lexical_cast] simple example doesn't work with vector<T> AMDG Ovanes Markarian wrote:
Just an addition:
Explicit specialization of std templates is legal. So if you _exactly_ know vector types for which your <<-operator should work you can write:
namespace std { template<> ostream& operator<< (ostream& os, const vector<MyTypeX>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } }
By the way there was a big discussion about this on std list and I fluently read the upcoming Standard draft and saw that this paragraph changed. I not any longer sure if this will be allowed with the new standard.
There has to be template to specialize. The std library doesn't have an overload of operator<< that matches std vector. Specialization can't change that. In Christ, Steven Watanabe _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Mon, Apr 7, 2008 at 3:26 PM, Andy Stevenson <andy.stevenson@uk.fujitsu.com> wrote:
The suggestions were to put it into namespace std or boost, both seem to work by the way.
However what is actually right here? Extending std seems distinctly non-std !
I really don't like either of them. Putting it in std:: is non-standard, and unsafe in practice as it's quite plausible that many people would want to give an implementation for it. Putting it in boost:: isn't really satisfactory either, since then it won't be simple to call in your normal code. Perhaps do something like this: template <typename T> struct space_separated_formatter { T &c; space_separated_formatter(T &c_) : c(c_) {} }; template <typename T> space_separated_formatter<T const> space_separated(T const &c) { return space_separated_formatter<T const>(c); } namespace std { template <typename T> ostream &operator<<(ostream &sink, space_separated_formatter<T> const &c) { copy( c.begin(), c.end(), ostream_iterator<typename T::value_type>(sink, " ") ); return sink; } } then boost::lexical_cast<std::string>( space_separated(myvec) ) or std::cout << space_separated(myvec); Still perhaps illegal, but probably safe in practice, especially if you wrap the type up into a namespace, since it'd make collisions unlikely. But whether it'd be worth it is a whole other story...

AMDG Scott McMurray wrote:
I really don't like either of them. Putting it in std:: is non-standard, and unsafe in practice as it's quite plausible that many people would want to give an implementation for it. Putting it in boost:: isn't really satisfactory either, since then it won't be simple to call in your normal code.
Perhaps do something like this:
template <typename T> struct space_separated_formatter { T &c; space_separated_formatter(T &c_) : c(c_) {} }; template <typename T> space_separated_formatter<T const> space_separated(T const &c) { return space_separated_formatter<T const>(c); } namespace std { template <typename T> ostream &operator<<(ostream &sink, space_separated_formatter<T> const &c) { copy( c.begin(), c.end(), ostream_iterator<typename T::value_type>(sink, " ") ); return sink; } }
then boost::lexical_cast<std::string>( space_separated(myvec) ) or std::cout << space_separated(myvec);
Still perhaps illegal, but probably safe in practice, especially if you wrap the type up into a namespace, since it'd make collisions unlikely.
In this case you can put operator<< in the namespace of space_separated_formatter, where it will be found by ADL. It's completely legal then. In Christ, Steven Watanabe

Scott, Thanks. What you're proposing is an elegant work around. I posted separately but it leaves me feeling I'm missing something about extensibility that the std/boost authors had in mind. Regards, Andy -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Scott McMurray Sent: 07 April 2008 23:10 To: boost-users@lists.boost.org Subject: Re: [Boost-users] [boost][lexical_cast] simple example doesn't workwith vector<T> On Mon, Apr 7, 2008 at 3:26 PM, Andy Stevenson <andy.stevenson@uk.fujitsu.com> wrote:
The suggestions were to put it into namespace std or boost, both seem to work by the way.
However what is actually right here? Extending std seems distinctly non-std !
I really don't like either of them. Putting it in std:: is non-standard, and unsafe in practice as it's quite plausible that many people would want to give an implementation for it. Putting it in boost:: isn't really satisfactory either, since then it won't be simple to call in your normal code. Perhaps do something like this: template <typename T> struct space_separated_formatter { T &c; space_separated_formatter(T &c_) : c(c_) {} }; template <typename T> space_separated_formatter<T const> space_separated(T const &c) { return space_separated_formatter<T const>(c); } namespace std { template <typename T> ostream &operator<<(ostream &sink, space_separated_formatter<T> const &c) { copy( c.begin(), c.end(), ostream_iterator<typename T::value_type>(sink, " ") ); return sink; } } then boost::lexical_cast<std::string>( space_separated(myvec) ) or std::cout << space_separated(myvec); Still perhaps illegal, but probably safe in practice, especially if you wrap the type up into a namespace, since it'd make collisions unlikely. But whether it'd be worth it is a whole other story... _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Yes, that's true... the std operator << is defined as: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<(basic_ostream<CharT, Traits>, some_overloaded_type const&); due some_overaloaded_type is not a template argument, the template can not be specialized on it, and therefore it is illegal to overload this operator. Andy, to your other post: standard only says that this is undefined behavior to overload std functions if it works with your compiler it does not mean it will always work and that it will not break existing code or cause some sleepless night to another developer why some other operator << then the std one is called. This is just a reminder, that not everything that compiles is automatically standard conform. Best Regards, Ovanes On 4/7/08, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Ovanes Markarian wrote:
Just an addition:
Explicit specialization of std templates is legal. So if you _exactly_ know vector types for which your <<-operator should work you can write:
namespace std { template<> ostream& operator<< (ostream& os, const vector<MyTypeX>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } }
By the way there was a big discussion about this on std list and I fluently read the upcoming Standard draft and saw that this paragraph changed. I not any longer sure if this will be allowed with the new standard.
There has to be template to specialize. The std library doesn't have an overload of operator<< that matches std vector. Specialization can't change that.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Ovanes, Thanks for this. I get the idea about 'just because it compiles doesn't mean it is std conformant'. I guess the thread has me curious about the extensibility of the ostream<< or the lexical_cast for that matter that depends on ostream<< extensibility being. I feel I must be missing something here that the std authors had in mind. Andy _____ From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Ovanes Markarian Sent: 07 April 2008 22:43 To: boost-users@lists.boost.org Subject: Re: [Boost-users] [boost][lexical_cast] simple example doesn't workwith vector<T> Yes, that's true... the std operator << is defined as: template<class CharT, class Traits> basic_ostream<CharT, Traits>& operator<<(basic_ostream<CharT, Traits>, some_overloaded_type const&); due some_overaloaded_type is not a template argument, the template can not be specialized on it, and therefore it is illegal to overload this operator. Andy, to your other post: standard only says that this is undefined behavior to overload std functions if it works with your compiler it does not mean it will always work and that it will not break existing code or cause some sleepless night to another developer why some other operator << then the std one is called. This is just a reminder, that not everything that compiles is automatically standard conform. Best Regards, Ovanes On 4/7/08, Steven Watanabe <watanabesj@gmail.com> wrote: AMDG Ovanes Markarian wrote:
Just an addition:
Explicit specialization of std templates is legal. So if you _exactly_ know vector types for which your <<-operator should work you can write:
namespace std { template<> ostream& operator<< (ostream& os, const vector<MyTypeX>& v) { copy(v.begin(), v.end(), ostream_iterator<T>(os, ";")); return os; } }
By the way there was a big discussion about this on std list and I fluently read the upcoming Standard draft and saw that this paragraph changed. I not any longer sure if this will be allowed with the new standard.
There has to be template to specialize. The std library doesn't have an overload of operator<< that matches std vector. Specialization can't change that. In Christ, Steven Watanabe _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Mon, Apr 7, 2008 at 6:56 PM, Andy Stevenson <andy.stevenson@uk.fujitsu.com> wrote:
Thanks for this. I get the idea about 'just because it compiles doesn't mean it is std conformant'. I guess the thread has me curious about the extensibility of the ostream<< or the lexical_cast for that matter that depends on ostream<< extensibility being. I feel I must be missing something here that the std authors had in mind.
The problem here is that you're trying to, effectively, add something to the standard library, which isn't really allowed. Nothing in ostream &operator<<(ostream &, std::vector<T>) is "yours" (a type you defined), so it's non-trivial, which isn't considered a problem since most often you aren't doing that (and it's still possible without too much trouble when you are). As Steven Watanabe pointed out, as soon as you're writing an operator<< for your own type, you simply define it in the same "place" (meaning namespace) as the type itself and everything will "just work" (thanks to ADL).
participants (5)
-
Alexander Nasonov
-
Andy Stevenson
-
Ovanes Markarian
-
Scott McMurray
-
Steven Watanabe