Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > > >From: "Jason House" <[EMAIL PROTECTED]> > > > > > 1. Is it at all useful/possible to use a lambda-like notation? > > > Thinking about it more, I don't know how doable it is for the first 3 > parameters... > > But what about: > > /* brain dead function to serve as example */ > std::string printable(char z) {return z=0?"\0":std::string(z);} > > char x[7] = "foobar"; > std::cout ><< io_format("{", "}", ", ", "'" << printable(_1) << "'") ><< "x = " << x; > > output: > x = {'f', 'o', 'o', 'b', 'a', 'r', '\0'} > > alternates like (printable(_1) or just "'" << _1 << "'" would also work. > > That makes the visitor possible, but also makes the inspiring case for > the extra inputs to io_format be a little more readable... This still wouldn't, in itself, support things like outputting indices, though, unless the entity being passed may hold state, such as a function object. It also looks like quite a bit more complex, apparently much of it just to be able to write "\'" << _1 << "\'" instead of "\'","\'". There's another issue: The type of the lambda expression would likely encode the expression, meaning you have an issue of how to store and retrieve it, unless you know the exact type of the object to retrieve. This is the code to retrieve the format_data object for a given type (given with "index"): template static format_data &format(std::basic_ostream &stream) { void *&void_ptr=stream.pword(index); if(!void_ptr) void_ptr=new format_data(default_data); return *static_cast *>(void_ptr); } How to do that, if the object being retrieved is an arbitrary type? Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > > >From: "Jason House" <[EMAIL PROTECTED]> > > > I had 2 thoughts today... > > > > 1. Is it at all useful/possible to use a lambda-like notation? > > In what way? Could you have given a rough syntax-example? > > An example in BLL is: > > std::for_each(v.begin(), v.end(), std::cout << _1 << '\n'); Thinking about it more, I don't know how doable it is for the first 3 parameters... But what about: /* brain dead function to serve as example */ std::string printable(char z) {return z=0?"\0":std::string(z);} char x[7] = "foobar"; std::cout << io_format("{", "}", ", ", "'" << printable(_1) << "'") << "x = " << x; output: x = {'f', 'o', 'o', 'b', 'a', 'r', '\0'} alternates like (printable(_1) or just "'" << _1 << "'" would also work. That makes the visitor possible, but also makes the inspiring case for the extra inputs to io_format be a little more readable... My original thoughts for the first 3 parameters was something like io_format<_>("start" << _1 << "middle" << _2 << "end") But I think that deciphering that properly in code would be tough, and might not actually provide any extra power (for the first 3 parameters). The only way that I see to get extra power would probably require making first, middle, last seperate inputs, but then you come right back to the "start, end, middle" verses "start, middle, end" ordering... :( > > 2. Why are we restricting the output to strings? > > That _is_ a natural question, isn't it? :) > > >Couldn't the types of the 3 delimiter strings actually be > >implicit template parameters? > >(the char/wchar versions made me think of that) > > Yes, that is how it currently works; Looks like I should read your code more thoroughly. I asked because I didn't remember any conclusion like that in the list discussion. Sorry about the stupid question :P ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > I had 2 thoughts today... > > 1. Is it at all useful/possible to use a lambda-like notation? In what way? Could you have given a rough syntax-example? An example in BLL is: std::for_each(v.begin(), v.end(), std::cout << _1 << '\n'); >In the past, I've liked the look of that a lot. >(the comments about alternate notation made me think of it) > > 2. Why are we restricting the output to strings? That _is_ a natural question, isn't it? :) >Couldn't the types of the 3 delimiter strings actually be >implicit template parameters? >(the char/wchar versions made me think of that) Yes, that is how it currently works; it deduces the types passed to the format function template, and returns an object of type format_type (analogous to many cases, such as bind1st/binder1st). Since all the string parameters have default to empty string, this is done by having three overloads of the format function template - for std::basic_string, const char * and const wchar_t *. That way, you can use "", L"", etc. as appropriate, for the default. As mentioned in some previous postings, a possibility for generalising the formatting could be to pass a "visitor" object to the format-function, instead of the strings, which is then invoked at the specific times during output (begin/end sequence, etc.). One could then also support things like line numbers and indentation, without hardcoding how this is done. It would also be possible to make a visitor object which took strings in the constructor, and gave the current semantics. This approach seems to require dynamical allocation of the format data, and virtual functions, though. Since this means quite a bit of change, I haven't done it so far, but I'm open to the possibility. An example of its use: // Line numbering visitor (could be included in the library) // // All virtual functions are included for illustration. In practice, the once with empty body could be omitted. template class numbering_type : public visitor_base { public: explicit numbering(int ln) : line_number(ln) {} virtual void start_sequence(std::basic_ostream &stream) {} virtual void end_sequence(std::basic_ostream &stream) {} virtual void element(std::basic_ostream &stream, const T &element) { stream << line_number << ' ' << element << '\n'; ++line_number; } private: int line_number; }; // The numbering function template returns a numbering_type object typedef std::vector vector; vector v; // Fill vector std::cout << format(numbering()) << v; Output: 1 - A 2 - B 3 - C etc. Thanks. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
I had 2 thoughts today... 1. Is it at all useful/possible to use a lambda-like notation? In the past, I've liked the look of that a lot. (the comments about alternate notation made me think of it) 2. Why are we restricting the output to strings? Couldn't the types of the 3 delimiter strings actually be implicit template parameters? (the char/wchar versions made me think of that) Just two quick thoughts. Overall, I like it a lot :) ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: io operations for stl containers?
> > I am afraid boost/io/format will be confusing in a sight of > presence of > > Boost.Format. > > I understand. Well, it's in a different namespace. I do not know why BTW. But even if it stays this way, I easily see a newbie looking for Boost.Format staff in your headers and vise-vesa > The directories follow the namespaces, so it has "std" and > "boost". STL is > only a subset of the standard library, so also for that > reason, I think > "std" would be more appropriate. OK. > This should be quite easy to add. The latter style is also > used in Reece > Dunn's list manipulator, which also deals with output for sequences. That would be great. > I don't have that much practice with it, but I've found > myself that I don't > have a problem remembering which parameter is what, in the > 3+2 optional > parameter list. Lack of verbosity may be considered one of > the advantages > over writing explicit output code. That is not the problem for the developer - when you actively working with library. But may be an issue for maintainer. Even if it's the same person. Let say you returns to the application written year ago and never used this formatting library meanwhile. Then I am afraid format("","","") could be a bit confusing. Gennadiy. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Rozental, Gennadiy" <[EMAIL PROTECTED]> > > #include > > #include > > #include > > I am afraid boost/io/format will be confusing in a sight of presence of > Boost.Format. I understand. Well, it's in a different namespace. > I would prefer (since it all about container output formatting) > > boost/io/container Well, it actually may handle any composite type, such as std::complex, std::pair, etc., as well. It also handles any sequence (using io::sequence(begin,end) ), not just containers. I used to call it "composite_format", but that was rather long... Using "io::format(...)", I think is quite succinct. > Also it could be stl instead of std, though it's the matter of taste. The directories follow the namespaces, so it has "std" and "boost". STL is only a subset of the standard library, so also for that reason, I think "std" would be more appropriate. > > std::cout << format("[", "]\n", " => ") > > << format("","","") > > << values; > > ... > > > Syntax > > -- > > format(, , , [ > element>, ])[.set_default_format()] > > format() > > I personally would really prefer verbose format specification. So I should > not remember what each of the parameters means by it's position. > Something along this lines: > > std::cout << start_elelment( "[" ) // if you need value > type_here. I am not sure Yes, you do, or it won't know which type to set it for. > << end_element( "]\n" ) > << element_delimeter( " => " ) > ... > << values; > > Or > > std::cout << format().start_elelment( "[" ).end_element( "]\n" > ).delimeter( " => " ) > ... > << values; > > Or mix of this styles. Or - the very best - all of them. This should be quite easy to add. The latter style is also used in Reece Dunn's list manipulator, which also deals with output for sequences. I don't have that much practice with it, but I've found myself that I don't have a problem remembering which parameter is what, in the 3+2 optional parameter list. Lack of verbosity may be considered one of the advantages over writing explicit output code. Thanks for the feedback. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: io operations for stl containers?
> #include > #include > #include I am afraid boost/io/format will be confusing in a sight of presence of Boost.Format. I would prefer (since it all about container output formatting) boost/io/container Also it could be stl instead of std, though it's the matter of taste. > std::cout << format("[", "]\n", " => ") > << format("","","") > << values; ... > Syntax > -- > format(, , , [ element>, ])[.set_default_format()] > format() I personally would really prefer verbose format specification. So I should not remember what each of the parameters means by it's position. Something along this lines: std::cout << start_elelment( "[" ) // if you need value type_here. I am not sure << end_element( "]\n" ) << element_delimeter( " => " ) ... << values; Or std::cout << format().start_elelment( "[" ).end_element( "]\n" ).delimeter( " => " ) ... << values; Or mix of this styles. Or - the very best - all of them. Gennadiy. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Hi. I've now uploaded the latest version of the composite stream operators library at Yahoo Files (http://groups.yahoo.com/group/boost/files/composite_stream_operators/) and the Sandbox (boost/io/format/ and libs/io/format).. Since the libraries in the Sandbox use the boost namespace, this one does the same. All components are in the boost::io namespace. There are no docs, yet, but there are several test programs, illustrating use for all supported types (the list of these are given below). I also include information here. Feedback is welcome. Examples of use: std::vector --- #include std::vector v; // Fill vector // Output (using user-changeable default format) std::cout << v; Output: [1,2,3,4,5,6,7,8,9,10] std::map #include typedef std::map map; typedef map::value_type value_type; map values; // Fill map std::cout << format("[", "]\n", " => ") << format("","","") << values; Output: [1 => A] [2 => B] [3 => C] Array --- #include int array[]={1,2,3,4,5,6,7,8,9,10}; std::cout << array << '\n' << format<_ (&)[N]>("", "", "\n") << array; Output: [1,2,3,4,5,6,7,8,9,10] 1 2 3 4 5 6 7 8 9 10 Here is a synopsis -- namespace boost::io - format - Set output formatting == Type options -- "_" - Any type "N" - Any size (for array) template_name<_> - Any instantiation of the given template (may need more "_"s, one for each parameter without default) Syntax -- format(, , , [, ])[.set_default_format()] format() If set_default_format() is used, it may be used without a stream, and it then sets the format for all streams. Examples -- stream << format >(...) // Set format for std::vector stream << format >(...) // Set format for any instantiation of std::vector stream << format<_>(...) // Set format for any type stream << format >(false) // Unsets format for std::vector It checks for format settings, going from the most specific to the most general, stopping when it has found a set format. E.g. for the above example, this means checking in the following order: std::vector std::vector<_> _ _ (any stream) The library sets the following default for all streams (the last format checked), which may be changed by the user. This default is set rather arbitrarily, and is open to change. This is so that no formatting is needed to be set, to get useful output: format<_>("[", "]", ",").set_default_format() - Sets format for all types, for all streams. It also handles wide character formatting: format(L"[", L"]", L",") sequence - Lets a sequence, given with start/end iterators, be output as the given type == Syntax -- sequence(, ) Examples -- #include std::vector v; // Fill vector std::cout << sequence<_>(v.begin(),v.begin()+10); Output: [1,2,3,4,5,6,7,8,9,10] typedef std::istream_iterator in; std::cout << sequence<_>(in(std::cin),in()); Input: 1 2 3 4 5 6 7 8 9 10 Output: [1,2,3,4,5,6,7,8,9,10] wrap - Lets a type be output using set format, even if it has its own output operator == Some types, such as std::complex, std::bitset, and boost::dynamic_bitset have already output stream operators defined, so to set their format, one may wrap the value before outputting. Syntax - wrap() Examples -- #include std::complex value(1.23, 2.34); std::cout << value << '\n' << wrap(value); Output: (1.23,2.34) [1.23,2.34] Supported types = Arrays std pair complex (has output operator, use wrap) vector list deque set multiset map multimap bitset (has output operator, use wrap) boost dynamic_bitset (has output operator, use wrap) The supported types may also be extended by the user. Header organisation boost/io/format --- |--- std |--- boost libs/format/io --- |--- tests Compatibility == The library uses standard C++, but isn't very portable currently. It has been tested on Intel C++ 7.0 and g++ 3.2. I plan to work on the portability, and should soon get it to work on MSVC, etc., as well. The names, syntax and semantics is open to suggestions for change. I hope Daryle Walker doesn't mind that this library is sharing the "io" directory and namespace, at the Sandbox. If so, I could change it from "io/format" to "io_format". Thanks for the patience to those who have waited for this update. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > typedef std::vector vector_char; > > > > vector_char values; > > > > // Fill with 'A', 'B', 'C' > > > > std::cout << io::format("[", "]", ", ", "\'", "\'") << values; > > > > Output: > > > > ['A', 'B', 'C'] > > > > However, is this overkill? > > It seems that way, especially considering that if it was a vector of > anything other than a fundamental type with std::cout << already defined > for it, you could add a second io::format("\'","\'","") and it > would work. Right. However, I've already implemented it, anyway, as an experimental feature. :) Besides, the two extra strings default to empty strings. > > Feedback is most welcome. > > Would possibly a function object for outputting the contained item be > better? [I first thought you meant a function object for outputting the _container_, not the elements, so I wrote the following section, before realising that you had meant for the elements. I address it afterwards] I've been thinking of the same, with regard to outputting the _container_ (not the element, itself). In an earlier posting, I mentioned the possibility of using function objects, as a way to generalising the handling of output. I also mentioned having the kind of function objects like BGL, i.e. "visitors". That is, rather than only overloading the operator(), it may provide several member functions, e.g.: class stream_visitor { public: void start(); void end(); void delimiter(); }; std::cout << format(stream_visitor(...)); One could then provide a function object which does what it currently does. There are issues with this, however. I've been thinking long and hard about how to provide this functionality. The issue is that the functors has to be stored somewhere, and being accessible. With the current version, all the format objects are the same type, so you know its type when it's stored and retrieved. However, if arbitrary (generic) functors are stored, you don't know its type, when you access it, when performing output. It's similar to trying to store different types in the same std::vector. There are solutions to this, and one is to use a common interface, and all functors inherit from that interface, and override the virtual functions. That would let you store them using a pointer to the interface. However, this means the overhead of a virtual function call per call to the member functions above. This may not be that much, but it's still also the issue that generic functors can't be used - they all have to inherit from the same interface. For this reason, I found that this could be a possible later addition, if we find that the added flexibility is worth it. Also, the current syntax could still be kept as a convenience, by having an overloaded constructor taking the strings, and creating the functor. So a change may be backwards compatible. > Here's a possibly mutilated example (I've never actually used > function objects before): > > std::ostream delimitted_char(std::ostream out, char x, std::string > first, std::string last); > > std::cout << io::format("[", "]", ", ", > bind("\'", 4, bind("\'", 3, delimitted_char))) Yes, it's possible, but I this seems to make it more complex than simply using io::format("[", "]", ",", "\'", "\'"), with the two last strings defaulted to empty strings. > > There's yet another alternative way this may be done, using "placeholder" > > types, i.e.: > > > > std::cout << io::format >(...); // Sets the format for all > > vectors > > std::cout << io::format<_>(...); // Sets the format for all types (defaults) > > > > This would avoid hardcoding any defaults, as the user could change it. > > > > The output routines could then check the formats in the following order, > > e.g. for "std::vector": > > > > If there's a format set for std::vector, use it, else > > if there's a format set for std::vector<_> (all vectors), use it, else > > use format for _. > > > > Comments? > > I like it :) I found it quite neat, as well. :) Interestingly, one important contribution of libraries are concepts and idioms. Since "_" is used as placeholder other places, making it mean "any type" here is reasonably intuitive, as well. > Using just _ scares me a bit... It would have to have a good default :) Well, it doesn't matter that much, as all the formats are user-settable. The library may provide a setting for _, but it can easily be set to something else by the user, in the same way. In fact, the current version in the Files (the first upload), has as "defaults" that all strings are empty. So the defaults have existed from the beginning, anyway. After all, you have to use _some_ format to print types for which no explicit format has been set. Being able to set this default explicitly, rather than hardcoding it in the library, should therefore be a good thing. In fact, I've made an implementation of the above, yesterday, and I'll just make some more tests, and upload it to the Files
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > typedef std::vector vector_char; > > vector_char values; > > // Fill with 'A', 'B', 'C' > > std::cout << io::format("[", "]", ", ", "\'", "\'") << values; > > Output: > > ['A', 'B', 'C'] > > However, is this overkill? It seems that way, especially considering that if it was a vector of anything other than a fundamental type with std::cout << already defined for it, you could add a second io::format("\'","\'","") and it would work. > > Feedback is most welcome. Would possibly a function object for outputting the contained item be better? Here's a possibly mutilated example (I've never actually used function objects before): std::ostream delimitted_char(std::ostream out, char x, std::string first, std::string last); std::cout << io::format("[", "]", ", ", bind("\'", 4, bind("\'", 3, delimitted_char))) Of course, the function object parameter should have a nice default to the << operator. > > > There was a suggestion for allowing generic formats, though, using > > > the same format for all instantiations of a template. The question is > how to > > > do it. The current version stores the format for each specific type, as > you > > > say. Volodya suggested a couple of ways it could be done, partial > > > specialisation, or storing the template name in a map. > > There's yet another alternative way this may be done, using "placeholder" > types, i.e.: > > std::cout << io::format >(...); // Sets the format for all > vectors > std::cout << io::format<_>(...); // Sets the format for all types (defaults) > > This would avoid hardcoding any defaults, as the user could change it. > > The output routines could then check the formats in the following order, > e.g. for "std::vector": > > If there's a format set for std::vector, use it, else > if there's a format set for std::vector<_> (all vectors), use it, else > use format for _. > > Comments? I like it :) Using just _ scares me a bit... It would have to have a good default :) The result would be intuitive, so I guess a use at your own risk is ok. In some ways, maybe it's good that items like char wouldn't use it :) ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > > std::vector > test; > > > > std::cout << test: // Using defaults > > > > (('A',1),('B',2),('C',3)) > > I would suspect that chars don't get output with '' around them... > Is there even a way to specify/change that? Something similar for > strings (along with an escape character) would be very handy for > strings. I've found a way this may be done. If you specify "start element" and "end element" strings, in addition, it may be done. Currently, it takes "start sequence", "end sequence", and "delimiter", so this would mean two (optional) more. E.g.: typedef std::vector vector_char; vector_char values; // Fill with 'A', 'B', 'C' std::cout << io::format("[", "]", ", ", "\'", "\'") << values; Output: ['A', 'B', 'C'] However, is this overkill? Even if the last two are optional, it means the output routines have to output (possibly empty) strings before and after each element, in addition to the delimiter. Feedback is most welcome. > > There was a suggestion for allowing generic formats, though, using > > the same format for all instantiations of a template. The question is how to > > do it. The current version stores the format for each specific type, as you > > say. Volodya suggested a couple of ways it could be done, partial > > specialisation, or storing the template name in a map. There's yet another alternative way this may be done, using "placeholder" types, i.e.: std::cout << io::format >(...); // Sets the format for all vectors std::cout << io::format<_>(...); // Sets the format for all types (defaults) This would avoid hardcoding any defaults, as the user could change it. The output routines could then check the formats in the following order, e.g. for "std::vector": If there's a format set for std::vector, use it, else if there's a format set for std::vector<_> (all vectors), use it, else use format for _. Comments? Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > > >From: "Jason House" <[EMAIL PROTECTED]> > > > > > Is there even a way to specify/change that? > > > > It isn't currently, as the fundamental types aren't handled as composite > > types, and therefore aren't formatted using any set format. Also, it seems > > it may not be possible in an obvious way. > > > > It appears to prefer the operator<<(char) stream member function, to this > > free function, as it isn't called when doing "std::cout << 'A';". > > :( > It would be a good question to figure out why that won't work, and how > to fix it... What happens, in general, if somebody want to override a > stream operator to do something else? Well, outputting UDTs work fine, as you can then overload the operator<<. However, as it's already overloaded, as a member function of the stream class, for the built-in types, it doesn't help to overload it for them. > String output probably uses > character output by default... it would be very bad to have a system > that made the string "string" (no quotes) output as 's''t''r''i''n''g' Yeah. :) basic_istream/basic_ostream have overloaded stream operators for CharType *, so they handle strings, in other words, the iostream versions of gets()/puts(). > > > Debugger friendly manipulation would be good. I still haven't thought > > > about how exactly outputting of an arbitrary composite variable will > > > work in the debugger by default... I agree that having a wrapper makes > > > it easy for the output formatting of general types, but actually being > > > able to execute "std::cout << my_suspect_variable" in the debugger > > > without premeditation still poses a significant problem. Why can't bugs > > > be predicted before you notice them? > > > > You're right, good point. Would it be possible to get some information on > > what kind of functions, if any, may be called in e.g. your debugger? From > > this, we may find what we can do. > > Well, I personally haven't gotten into the habit of calling functions > for any debugger. Me neither. > I know that gdb allows that... and last that I tried > it under the cygwin port, it wasn't very stable (but I kind of expect > that in a cygwin port). I do also remember hitting trouble trying to > call templated types. I believe that it could make calls to templated > functions, but you needed to know the "real" name for the function... > The base function name plus extra characters in order to distinguish > it... I might have gotten the "real" name off the call stack or > something like that... > > Does that help to define "my debugger"? I would hope to make it work > for as many debuggers as possible (provided that they at least support > making function calls) Well, I guess that in either case, this may be handled through layering, i.e. possibly providing convenience functions which calls the overloaded stream operators, if the latter is difficult to call from a debugger. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Vladimir Prus" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > Right. There was a suggestion for allowing generic formats, though, using > > the same format for all instantiations of a template. The question is how > > to do it. The current version stores the format for each specific type, as > > you say. Volodya suggested a couple of ways it could be done, partial > > specialisation, or storing the template name in a map. However, it could be > > hard to use the latter, as it could be hard to find the right type to look > > up, when outputting, given that you have specific types, not templates. > > Uhm... I meant that the right type should be explicitly written down: > > template > ostream& operator<<(ostream&, const vector& v) > { > const composite_format& cf = composite_format::get("vector"); > } > > not nice, but should work. Ah, I see. That would work. > > If partial specialisation was used instead, you'd still need to specify the > > full type (even if only the generic format is set), and then, how to > > differentiate between specific and generic format? For example: > > > > std::cout << io::set_format >(...); // > > Uses partial specialisation of class template set_format for std::vector, > > setting generic format > > Oh... so here's the gotcha! I definitely don't like this syntax for setting > format for *all* vectors. Me neither. It looks like it sets it for a specific type. > Maybe, we can go even simpler way: introduce > separate classes for all container kinds. BGL already has vecS, setS, and so > on. The syntax for setting format will be > > cout << io::set_format(...) ; Yeah, that could be a way. > > > >From what I have thought about it, allowing a generic type creates room > > > for unexpected behavior in output when there are composite types > > > containing composite types, and somewhere along the lines a *generic > > > type* default is overridden. There might be a specific reason for a > > > bunch of lists inside of a composite type to have a specific set of > > > delimiters... but it probably isn't desired for the lists inside those > > > lists to be forced into using the same delimiters. > > > > Right. Well, as mentioned, the current version uses format for specific > > types, so in that case, you could format each part of the nested container > > as you wanted, as shown with the 2D-array, which of course is an array of > > arrays. > > I think that nested containers should be handled in a more explicit way. Why > can't we allow to explicitly set braces/delimiters for container at certain > nesting level: > > cout << io::set_format(...) > > would change delimiters only for top-level container. The question is that the > same code can be called both from top-level and when outputting some > container. It would be possible to just reset nesting level, and restore it > after outputting. Yeah, like with I/O state savers. I'll do some more experimentation with this, and others are free to do the same with the code, of course. I haven't yet updated it much, from the version at Yahoo Files, since it hasn't really been certain what the design should be. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > > >From: "Jason House" <[EMAIL PROTECTED]> > > I would suspect that chars don't get output with '' around them... > > Right. I was just thinking C++ code, here. :) > > > Is there even a way to specify/change that? > > It isn't currently, as the fundamental types aren't handled as composite > types, and therefore aren't formatted using any set format. Also, it seems > it may not be possible in an obvious way. > > It appears to prefer the operator<<(char) stream member function, to this > free function, as it isn't called when doing "std::cout << 'A';". :( It would be a good question to figure out why that won't work, and how to fix it... What happens, in general, if somebody want to override a stream operator to do something else? String output probably uses character output by default... it would be very bad to have a system that made the string "string" (no quotes) output as 's''t''r''i''n''g' > > :( > > Debugger friendly manipulation would be good. I still haven't thought > > about how exactly outputting of an arbitrary composite variable will > > work in the debugger by default... I agree that having a wrapper makes > > it easy for the output formatting of general types, but actually being > > able to execute "std::cout << my_suspect_variable" in the debugger > > without premeditation still poses a significant problem. Why can't bugs > > be predicted before you notice them? > > You're right, good point. Would it be possible to get some information on > what kind of functions, if any, may be called in e.g. your debugger? From > this, we may find what we can do. Well, I personally haven't gotten into the habit of calling functions for any debugger. I know that gdb allows that... and last that I tried it under the cygwin port, it wasn't very stable (but I kind of expect that in a cygwin port). I do also remember hitting trouble trying to call templated types. I believe that it could make calls to templated functions, but you needed to know the "real" name for the function... The base function name plus extra characters in order to distinguish it... I might have gotten the "real" name off the call stack or something like that... Does that help to define "my debugger"? I would hope to make it work for as many debuggers as possible (provided that they at least support making function calls) ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Terje Slettebø wrote: > Right. There was a suggestion for allowing generic formats, though, using > the same format for all instantiations of a template. The question is how > to do it. The current version stores the format for each specific type, as > you say. Volodya suggested a couple of ways it could be done, partial > specialisation, or storing the template name in a map. However, it could be > hard to use the latter, as it could be hard to find the right type to look > up, when outputting, given that you have specific types, not templates. Uhm... I meant that the right type should be explicitly written down: template ostream& operator<<(ostream&, const vector& v) { const composite_format& cf = composite_format::get("vector"); } not nice, but should work. > Overloading of class templates might have helped, here. E.g.: > > std::cout << io::set_format >(...); // Set > specific format (io::format is a class template) > std::cout << io::set_format(...); // Set generic format for > std::vector (io::format overloaded with a version taking template template > parameter, and specialised for std::vector) Yes, it would definitely have helped. > If partial specialisation was used instead, you'd still need to specify the > full type (even if only the generic format is set), and then, how to > differentiate between specific and generic format? For example: > > std::cout << io::set_format >(...); // > Uses partial specialisation of class template set_format for std::vector, > setting generic format Oh... so here's the gotcha! I definitely don't like this syntax for setting format for *all* vectors. Maybe, we can go even simpler way: introduce separate classes for all container kinds. BGL already has vecS, setS, and so on. The syntax for setting format will be cout << io::set_format(...) ; > > >From what I have thought about it, allowing a generic type creates room > > > > for unexpected behavior in output when there are composite types > > containing composite types, and somewhere along the lines a *generic > > type* default is overridden. There might be a specific reason for a > > bunch of lists inside of a composite type to have a specific set of > > delimiters... but it probably isn't desired for the lists inside those > > lists to be forced into using the same delimiters. > > Right. Well, as mentioned, the current version uses format for specific > types, so in that case, you could format each part of the nested container > as you wanted, as shown with the 2D-array, which of course is an array of > arrays. I think that nested containers should be handled in a more explicit way. Why can't we allow to explicitly set braces/delimiters for container at certain nesting level: cout << io::set_format(...) would change delimiters only for top-level container. The question is that the same code can be called both from top-level and when outputting some container. It would be possible to just reset nesting level, and restore it after outputting. - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Hi Terje, [...] > > But you don't write library, put a seal on it, and stop. There's nothing > > wrong > > > with making it more flexible when users demand it. As it stands, only few > > persons are interested in the simplest facilities. Is it worth spending > > time > > on completely generic/flexible solution if no-one has expressed desire > > for it? > > Right, again. What do you think of the Boost.Tuple approach? It's sensible. OTOH, it's limited for one type, which is simpler. > >1. Operators use fixed format: bracked list with commas between values for > >vector, for example. > >2. Manipulators are provided to set brackets and separators. > > > >I had implemented the second approach some time ago, but it turned out > > that was overkill. So, 1) looks better now. > > Boost.Tuple uses the second approach, and it seems it can be useful to > provide the possibility to change the separators. It's still a quite simple > solution. As I've said previously, your solution appears simple enough to me, so I've no problem with that kind of flexibily. The only issues are 1. How to specify formatting style for all vectors, or for all sets, etc. 2. How to handle nested containers. I'll get to this in another email. - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > > > > std::vector > test; > > > > std::cout << test: // Using defaults > > > > (('A',1),('B',2),('C',3)) > > I would suspect that chars don't get output with '' around them... Right. I was just thinking C++ code, here. :) > Is there even a way to specify/change that? It isn't currently, as the fundamental types aren't handled as composite types, and therefore aren't formatted using any set format. Also, it seems it may not be possible in an obvious way. For example, the following addition to the header doesn't work: template std::basic_ostream &operator<< (std::basic_ostream &stream,char value) { typedef basic_composite_format format_type; const format_type &format=format_type::format(stream); stream << format.start; stream.operator<<(value); stream << format.end; return stream; } It appears to prefer the operator<<(char) stream member function, to this free function, as it isn't called when doing "std::cout << 'A';". > > In this case, it's not possible to set the format for each type separately. > > Maybe it could be good to keep that feature of the current composite > > operators, as well, something like: > > > > typedef std::pair map; > > typedef std::vector map_list; > > > > map_list test; > > > > std::cout << io::set_delimiter("\n") << test; > > > > Output: > > > > (('A',1) > > ('B',2) > > (C,3)) > > so basically, you would like to combine tuple-like output specification > (ie for all tuples) and type specific such as composite_format? I was thinking of that, yes. As well as a default, possibly user-settable, for any type not having set an explicit format. This would let you control the formatting in layers, so to speak: - You could use/set the default format for all types. - You could use/set the format for all instantiations of a given template, e.g. std::vector. - You could use/set the format for specific types. If possible, it would apply the most specific format set (i.e. it would prefer 3 to 2, to 1). Another thing is if this layering is practically possible. :) We get into this below here. > > template > > inline std::basic_ostream& > > operator<<(std::basic_ostream& o, > >const cons& t) > > > > As you say, this may be a problem to call from a debugger, unless it > > supports calling function templates. If one need to call it from a debugger, > > one could always wrap the code in a function. > > :( > Debugger friendly manipulation would be good. I still haven't thought > about how exactly outputting of an arbitrary composite variable will > work in the debugger by default... I agree that having a wrapper makes > it easy for the output formatting of general types, but actually being > able to execute "std::cout << my_suspect_variable" in the debugger > without premeditation still poses a significant problem. Why can't bugs > be predicted before you notice them? You're right, good point. Would it be possible to get some information on what kind of functions, if any, may be called in e.g. your debugger? From this, we may find what we can do. > > There was a suggestion for allowing generic formats, though, using > > the same format for all instantiations of a template. The question is how to > > do it. The current version stores the format for each specific type, as you > > say. Volodya suggested a couple of ways it could be done, partial > > specialisation, or storing the template name in a map. However, it could be > > hard to use the latter, as it could be hard to find the right type to look > > up, when outputting, given that you have specific types, not templates. > > > > Overloading of class templates might have helped, here. E.g.: > > > > std::cout << io::set_format >(...); // Set > > specific format (io::format is a class template) > > std::cout << io::set_format(...); // Set generic format for > > std::vector (io::format overloaded with a version taking template template > > parameter, and specialised for std::vector) > > Well, would cause trouble because the std::vector requires > extra arguments... I don't think you could get that to compile. True, it doesn't, because it's not currently legal C++. :) That's what I meant with "Overloading of class templates might have helped, here." It's not possible to overload class templates. However, this is mentioned as a possible extension, in the "Future Directions" chapter of Josuttis/Vandevoorde. Together with partial specialisation of function templates, etc. > Using > a string might work... but using it as a template argument would > probably cause trouble. Yes, you can't use string literals as template parameters. > I don't know if there is a way to use partial > template specialization. There is, as I showed in the following example. However, it means you have to provide the parameters to the template, as well (e.g. std::vector), even if you just mean to set the format for any instantiation of the template. > There was a recent post about convertin
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > > >From: "Jason House" <[EMAIL PROTECTED]> > > > Terje Slettebø wrote: > > > In a way, something good came from it, as well: I've recently looked at > > > Boost.Tuple, and I see that they have I/O operators defined (in > > > tuple_io.hpp). > > > > Well, it definitely seems like the tuples were thinking along similar > > lines with a start, middle, and stop delimiters. > > The documentation brings up a point about parseability of data streams. > > It doesn't quite make sense to me that there should be restriction to a > > single character in order to to make things uniquely parseable. If it's > > a fixed sequence of characters, I don't see how that makes it any > > significantly less parseable... Maybe I'm missing something? > > The docs says: > > "Note that extracting tuples with std::string or C-style string elements > does not generally work, since the streamed tuple representation may not be > unambiguously parseable." > > It's not about the delimiters. which it seems you mean, but about the tuple > elements. Consider: > > tuple test; > > stream >> test; // Stream contains "a string, with comma, 123" > > Here, it can't know that the first comma is part of the string, and not > meant to separate elements. Not to mention that it would stop after "a", due > to the space character. you're right... I was thinking that they were referring to the delimiters not being strings (and forced to be just characters). If the > I agree that it should be possible to have multi-character delimiters, > without creating parsing problems. It could be an idea to keep this, as it > may make for more flexible output. Even single-character delimiters is quite > flexible, as you can even get each element on its own line, by using '\n' as > the element separator. To look again at one example of how the tuple way > might work: > > std::vector > test; > > std::cout << test: // Using defaults > > (('A',1),('B',2),('C',3)) I would suspect that chars don't get output with '' around them... Is there even a way to specify/change that? Something similar for strings (along with an escape character) would be very handy for strings. Inside C++ code, a start and stop character of " and an escape of \ is used... I am not familiar with what serialization code is available, but I would suspect there might be a feature like that already in there somewhere. > In this case, it's not possible to set the format for each type separately. > Maybe it could be good to keep that feature of the current composite > operators, as well, something like: > > typedef std::pair map; > typedef std::vector map_list; > > map_list test; > > std::cout << io::set_delimiter("\n") << test; > > Output: > > (('A',1) > ('B',2) > (C,3)) so basically, you would like to combine tuple-like output specification (ie for all tuples) and type specific such as composite_format? > You might also have a non-template overload of the manipulators, which sets > the delimiters for all types, as done in tuples. > > This may also have a positive effect on a serialisation library: The > standard types will have default stream operators. > > > It does enable defaults and allows a way to customize each spacer > > individually, which is a good addition. I think the ability to set all > > 3 also is a must-have :) > > Yeah, I think that's useful, too. :) > > > The tuple functions, as provided should be extremely easy to call from a > > debugger since there is no templating going on. > > Actually, there is. They are defined in tuple_io.hpp as: > > template > inline std::basic_ostream& > operator<<(std::basic_ostream& o, >const cons& t) > > As you say, this may be a problem to call from a debugger, unless it > supports calling function templates. If one need to call it from a debugger, > one could always wrap the code in a function. :( Debugger friendly manipulation would be good. I still haven't thought about how exactly outputting of an arbitrary composite variable will work in the debugger by default... I agree that having a wrapper makes it easy for the output formatting of general types, but actually being able to execute "std::cout << my_suspect_variable" in the debugger without premeditation still poses a significant problem. Why can't bugs be predicted before you notice them? > There was a suggestion for allowing generic formats, though, using > the same format for all instantiations of a template. The question is how to > do it. The current version stores the format for each specific type, as you > say. Volodya suggested a couple of ways it could be done, partial > specialisation, or storing the template name in a map. However, it could be > hard to use the latter, as it could be hard to find the right type to look > up, when outputting, given that you have specific types, not templates. > > Overloading of class templates might have helped, here. E.g.: > > std::cout << io::set_format >(...); // Set >
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > > >From: "Vladimir Prus" <[EMAIL PROTECTED]> > > > > Sorry for having taken so long to respond to these messages. I felt a need > > for a break, to consider how it might be done. > > I was wondering about this line of discussion earlier today... wondering > if it died on the vine or not. I'm glad to see that it hasn't Right. After I had sent it, I found that "break" wasn't quite right. I meant that I had been considering it, including what had been said in the thread. Specifically, like I said in an earlier posting, I was wondering if there was enough commonality to warrant a library implementation. Then I happened to look more into Boost.Tuple, and realised that even a simple solution could be useful, as you and others have pointed out, as well. > > In a way, something good came from it, as well: I've recently looked at > > Boost.Tuple, and I see that they have I/O operators defined (in > > tuple_io.hpp). > > Well, it definitely seems like the tuples were thinking along similar > lines with a start, middle, and stop delimiters. > The documentation brings up a point about parseability of data streams. > It doesn't quite make sense to me that there should be restriction to a > single character in order to to make things uniquely parseable. If it's > a fixed sequence of characters, I don't see how that makes it any > significantly less parseable... Maybe I'm missing something? The docs says: "Note that extracting tuples with std::string or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable." It's not about the delimiters. which it seems you mean, but about the tuple elements. Consider: tuple test; stream >> test; // Stream contains "a string, with comma, 123" Here, it can't know that the first comma is part of the string, and not meant to separate elements. Not to mention that it would stop after "a", due to the space character. I agree that it should be possible to have multi-character delimiters, without creating parsing problems. It could be an idea to keep this, as it may make for more flexible output. Even single-character delimiters is quite flexible, as you can even get each element on its own line, by using '\n' as the element separator. To look again at one example of how the tuple way might work: std::vector > test; std::cout << test: // Using defaults (('A',1),('B',2),('C',3)) In this case, it's not possible to set the format for each type separately. Maybe it could be good to keep that feature of the current composite operators, as well, something like: typedef std::pair map; typedef std::vector map_list; map_list test; std::cout << io::set_delimiter("\n") << test; Output: (('A',1) ('B',2) (C,3)) Or, generating program-code like listing: std::cout << io::set_format("{\n","}\n",",\n") << io::set_format("{","}",", "} << test; { {'A', 1}, {'B', 2}, {'C', 3} } Maybe also: std::cout << io::set_format("(\n",")\n","\n") << io::set_indent(2) << test; ( ('A',1) ('B',2) ('C',3) ) You might also have a non-template overload of the manipulators, which sets the delimiters for all types, as done in tuples. This may also have a positive effect on a serialisation library: The standard types will have default stream operators. > It does enable defaults and allows a way to customize each spacer > individually, which is a good addition. I think the ability to set all > 3 also is a must-have :) Yeah, I think that's useful, too. :) > The tuple functions, as provided should be extremely easy to call from a > debugger since there is no templating going on. Actually, there is. They are defined in tuple_io.hpp as: template inline std::basic_ostream& operator<<(std::basic_ostream& o, const cons& t) As you say, this may be a problem to call from a debugger, unless it supports calling function templates. If one need to call it from a debugger, one could always wrap the code in a function. > I think that if when > composite_format matures, there should be a way to add non-templated > calls to change defaults. > maybe: > namespace composite_format{ > namespace tuple{ > ... set_open(char x){ return composite_format_open(x); } > } > } The manipulators might also be handled the same way as above, wrapping them in the function. > Actually that example doesn't quite work because is not well > defined. The previous discussion of composite_fromat (or at least the > code presented) did not allow for a generic class of types, and only > provided functionality for a very specific type. Right. There was a suggestion for allowing generic formats, though, using the same format for all instantiations of a template. The question is how to do it. The current version stores the format for each specific type, as you say. Volodya suggested a couple of ways it could be done, partial specialisation, or storing the tem
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > > >From: "Vladimir Prus" <[EMAIL PROTECTED]> > > Sorry for having taken so long to respond to these messages. I felt a need > for a break, to consider how it might be done. I was wondering about this line of discussion earlier today... wondering if it died on the vine or not. I'm glad to see that it hasn't, and that someone has been trying to think deeper into the application... > In a way, something good came from it, as well: I've recently looked at > Boost.Tuple, and I see that they have I/O operators defined (in > tuple_io.hpp). Well, it definitely seems like the tuples were thinking along similar lines with a start, middle, and stop delimiters. The documentation brings up a point about parseability of data streams. It doesn't quite make sense to me that there should be restriction to a single character in order to to make things uniquely parseable. If it's a fixed sequence of characters, I don't see how that makes it any significantly less parseable... Maybe I'm missing something? It does enable defaults and allows a way to customize each spacer individually, which is a good addition. I think the ability to set all 3 also is a must-have :) The tuple functions, as provided should be extremely easy to call from a debugger since there is no templating going on. I think that if when composite_format matures, there should be a way to add non-templated calls to change defaults. maybe: namespace composite_format{ namespace tuple{ ... set_open(char x){ return composite_format_open(x); } } } Actually that example doesn't quite work because is not well defined. The previous discussion of composite_fromat (or at least the code presented) did not allow for a generic class of types, and only provided functionality for a very specific type. > Maybe these routines could be generalised, and used for any > composite/compound type, including tuples? generic type = map, list, tuple specific type = map, map, list, etc... I should try to think about this more than I have :( >From what I have thought about it, allowing a generic type creates room for unexpected behavior in output when there are composite types containing composite types, and somewhere along the lines a *generic type* default is overridden. There might be a specific reason for a bunch of lists inside of a composite type to have a specific set of delimiters... but it probably isn't desired for the lists inside those lists to be forced into using the same delimiters. There is also room for trouble when the delimiters for both a generic type and a specific type have been set... I'd think that in general, the generic type would be lower precedence. But what if the generic type was set more recently? Should there be two forms for setting a generic type's delimiters? > If it's good enough for the standard library (given that Boost.Tuple have > been accepted in the Library TR), it may be good enough for the other types, > as well. :) I hope so :) ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Vladimir Prus" <[EMAIL PROTECTED]> Sorry for having taken so long to respond to these messages. I felt a need for a break, to consider how it might be done. In a way, something good came from it, as well: I've recently looked at Boost.Tuple, and I see that they have I/O operators defined (in tuple_io.hpp). To quote from the docs: --- Start quote --- Streaming The global operator<< has been overloaded for std::ostream such that tuples are output by recursively calling operator<< for each element. Analogously, the global operator>> has been overloaded to extract tuples from std::istream by recursively calling operator>> for each element. The default delimiter between the elements is space, and the tuple is enclosed in parenthesis. For Example: tuple a(1.0f, 2, std::string("Howdy folks!"); cout << a; outputs the tuple as: (1.0 2 Howdy folks!) The library defines three manipulators for changing the default behavior: - set_open(char) defines the character that is output before the first element. - set_close(char) defines the character that is output after the last element. - set_delimiter(char) defines the delimiter character between elements. Note, that these manipulators are defined in the tuples subnamespace. For example: cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a; outputs the same tuple a as: [1.0,2,Howdy folks!] The same manipulators work with operator>> and istream as well. Suppose the cin stream contains the following data: (1 2 3) [4:5] The code: tuple i; tuple j; cin >> i; cin >> tuples::set_open('[') >> tuples::set_close(']') >> tules::set_delimiter(':'); cin >> j; reads the data into the tuples i and j. Note that extracting tuples with std::string or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable. --- End quote --- Maybe these routines could be generalised, and used for any composite/compound type, including tuples? If it's good enough for the standard library (given that Boost.Tuple have been accepted in the Library TR), it may be good enough for the other types, as well. :) > Terje Slettebø wrote: > >>From: "Jason House" <[EMAIL PROTECTED]> > > > > > >>Terje Slettebø wrote: > >> > >> > >>>Regarding this project. I've got doubts about the viability of it. > >> > >>Well, I'm glad you've given it a greater level of thought. I really like > > > > the idea > > > >>of the composite_format, and probably should try to do the same :) > > > > > > Thanks for your feedback. I like the idea, as well. We have I/O for single > > objects, but no specific way for composites. The question is if we should > > have that. :) Maybe the reason we don't have it, yet, is that it may be hard > > to come up with a system that is general enough, yet easy to use. > > Most likely I don't need to say it again, but having fixed i/o operators with > fixed output format is better that have nothing. As you've noticed, my > original motivation was debugging output, and I still find this important enough. You're right. That was probably the motivation for Boost.Tuple's stream operators, as well: A minimal, easy to use interface, with sensible defaults. > >>>One thing is to create something useful. Another thing is to create > >>>something useful as a _library_ component. As has been noted regarding > >>>application and library development, application development and library > >>>development is typically quite different. With an application, you > > > > typically have quite specific requirements. With a library component, however, > > it's about anticipating future use. Or making something general enough to be > >>>useful as a library component. > > But you don't write library, put a seal on it, and stop. There's nothing wrong > with making it more flexible when users demand it. As it stands, only few > persons are interested in the simplest facilities. Is it worth spending time > on completely generic/flexible solution if no-one has expressed desire for it? Right, again. What do you think of the Boost.Tuple approach? In your original posting, you said: >I was thinking about > > > > >and so on. There are basically two approaches: > >1. Operators use fixed format: bracked list with commas between values for >vector, for example. >2. Manipulators are provided to set brackets and separators. > >I had implemented the second approach some time ago, but it turned out that >was overkill. So, 1) looks better now. Boost.Tuple uses the second approach, and it seems it can be useful to provide the possibility to change the separators. It's still a quite simple solution. > >>Very true, but some libraries are useful simply because they're simply > > code that > >>people would write themselves over and over... only done in a better way. > > +1. I've tried to make the same point above. You both succeeded. :) > >>written default for this makes it all worth it for me! The
RE: [boost] Re: io operations for stl containers?
I have followed this discussion with great interest. I feel that the lack of an easy, 'library' 'standard' way of 'outputting' STL objects is a major turnoff to their use. There is persistent re-invention of wheels. Some users may have their own special ideas about format, but a default would be easy and essential, and be enough for most people. If it can be used from debug tools, better still, but this should not deter work from the promising start to allow std::cout << list;. Paul Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 Mobile mailto:[EMAIL PROTECTED] mailto:[EMAIL PROTECTED] > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED]]On Behalf Of Terje Slettebø > Sent: Friday, February 07, 2003 9:38 PM > To: Boost mailing list > Subject: Re: [boost] Re: io operations for stl containers? > > The point with my posting was also to solicit feedback from others on the > issue, what they think about it, what it could be used for. It would help > define the application domain (also called problem domain). > > > > One thing is to create something useful. Another thing is to create > > > something useful as a _library_ component. As has been noted regarding > > > application and library development, application development and library > > > development is typically quite different. With an application, you > typically > > > have quite specific requirements. With a library component, however, > it's > > > about anticipating future use. Or making something general enough to be > > > useful as a library component. > > > > Very true, but some libraries are useful simply because they're simply > code that > > people would write themselves over and over... only done in a better way. > > Yeah. Also, Björn Karlsson had an informal questionnaire on the list a while > ago, about what people were using Boost for, and it turned out to be > especially the simple components (not necessarily simple in implementation, > by all means, but simple in concept) which were used, such as ref, bind, > function objects, the smart pointers, etc. > > These are components which, as I mentioned, does one thing, and one thing > well. That makes it easier to use/reuse these components in different > contexts, as they are like building blocks. > > Of course "one thing" may be anything. In the case of MPL, it's a framework > for metaprogramming, where each component does one thing. Thus, it provides > a "language" for making things. > > > In the > > current state of discussion, it sounds like something that I would > definitely > > use. I've implemented poor versions on the fly in the past... always more > > specific than composite_format... One big use of special display > > functions/operators is that you can call them from the debugger. If there > was a > > debug-time friendly version of composite object output functions... and > all I > > needed to do was #include a specific header, that would be absolutely > fantastic! > > Aha. Good point. > > > > You may do this: > > > > > > for(MapList::const_iterator i=list.begin(); i!=list.end(); ++i) > > > std::cout << '[' << i->first << ',' << i->second << "]\n"; > > > > > > Or you may do: > > > > > > std::cout << composite_format("[", "]", "\n") << list; > > > > > > The question is, is it worth it? > > > > > > Of course, having defaults, the latter may be reduced to: > > > > > > std::cout << list; > > > > I absolutely hate not being able to do this last one by default. > It would certainly be useful to come up with what we'd like to be able to > do. We can consider this "time out", for reconsidering what we'd like to > have. > > > Regards, > > Terje > > ___ > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost > ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Vladimir Prus wrote: > >>I'm pulling at stings, but there has to be good stuff to add if we come up > > > > with > > > >>the right aspect to develop. I have never heard of a library designed for > >>evaluation of debug-time expressions... It would be interesting to see > > > > how > > > >>powerful of a "compile-time debugger enhancement" concept we could come up > > > > with. > > > >>Why stop with just debugging symbols? Make an army of debugging > > > > functions... > > This sounds interesting, but I'm not sure what those other functions could be. I agree... I have only the fogiest of ideas as to what that would be... For starters, a display function for each composite object type. One very serious complication with templated types, is that it might very well be an army of functions... Will debuggers perform type matching similar to a compiler? Or would the template parameters need to be explicitely stated? In addition, what about overrides to the basic output characteristics? Seperation characters is one thing,but an almost more important one would be output suppression... Like having a map output all the keys, but skipping all the values... (likely boiling down to a pair outputting one of the two items inside of it)... When I was thinking of extra support functions, I was thinking of the override/suppression concept... As far as what else, I don't know... but again, even such a basic functionality would be great to have in a #included library header :) The other potential issue that I have is that for the library to be most useful, you should be able to have output functions for composite objects available to you by default... maybe something like adding a macro to replace typedef... like maybe #ifdef COMPOSITE_TYPE_DEBUG #define COMPOSITE_TYPE(x,y) \ typedef x y; \ { \ /* force compiler to make output function */ y boost_dummy_variable; \ boost::composit_io::details::null << boost_summy_variable; \ } #else #define COMPOSITE_TYPE(x,y) typedef x y; #endif of course, that might not be the best approach... I think #defines are avoided... but hopefully the concept is clear... ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Terje Slettebø wrote: From: "Jason House" <[EMAIL PROTECTED]> Terje Slettebø wrote: Regarding this project. I've got doubts about the viability of it. Well, I'm glad you've given it a greater level of thought. I really like the idea of the composite_format, and probably should try to do the same :) Thanks for your feedback. I like the idea, as well. We have I/O for single objects, but no specific way for composites. The question is if we should have that. :) Maybe the reason we don't have it, yet, is that it may be hard to come up with a system that is general enough, yet easy to use. Most likely I don't need to say it again, but having fixed i/o operators with fixed output format is better that have nothing. As you've noticed, my original motivation was debugging output, and I still find this important enough. [...] It may actually be easier to come up with a system for serialisation, at least when it comes to the serialised format, since the format to use for serialisation may be easier to define. However, for operators for human-readable I/O, there's a potentionally large variation in how you might want to do it. True. But there are some limits to what you could reasonably do by outputting composite objects. For example, generation of code, or html, or something, is not easily feasible. In fact, I cannot suggest any "advances" usage which is not close to serialization. And, sure enough, I don't want to use serialization for debug output. Your current code is 4K. You cannot make serialization library of that size. One thing is to create something useful. Another thing is to create something useful as a _library_ component. As has been noted regarding application and library development, application development and library development is typically quite different. With an application, you typically have quite specific requirements. With a library component, however, it's about anticipating future use. Or making something general enough to be useful as a library component. But you don't write library, put a seal on it, and stop. There's nothing wrong with making it more flexible when users demand it. As it stands, only few persons are interested in the simplest facilities. Is it worth spending time on completely generic/flexible solution if no-one has expressed desire for it? Very true, but some libraries are useful simply because they're simply code that people would write themselves over and over... only done in a better way. +1. I've tried to make the same point above. written default for this makes it all worth it for me! The for loop has no chance of being evaluated properly in a debugger, but a debugger can likely call the << operator with less difficulty. Right. +1, again. I'm pulling at stings, but there has to be good stuff to add if we come up with the right aspect to develop. I have never heard of a library designed for evaluation of debug-time expressions... It would be interesting to see how powerful of a "compile-time debugger enhancement" concept we could come up with. Why stop with just debugging symbols? Make an army of debugging functions... This sounds interesting, but I'm not sure what those other functions could be. - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > Regarding this project. I've got doubts about the viability of it. > > Well, I'm glad you've given it a greater level of thought. I really like the idea > of the composite_format, and probably should try to do the same :) Thanks for your feedback. I like the idea, as well. We have I/O for single objects, but no specific way for composites. The question is if we should have that. :) Maybe the reason we don't have it, yet, is that it may be hard to come up with a system that is general enough, yet easy to use. Since I posted this, I've been reading the discussion on serialisation/persistence, such as Jens Maurer's, and Robert Ramey's recently reviewed serialisation library. It seems there were similar issues there: It was hard to find one way of doing it, which could be generally agreed on. It may actually be easier to come up with a system for serialisation, at least when it comes to the serialised format, since the format to use for serialisation may be easier to define. However, for operators for human-readable I/O, there's a potentionally large variation in how you might want to do it. In the case of the composite operators, nobody has complained about lack of generality, or ease of use, but I've been thinking about this issue, myself. The point with my posting was also to solicit feedback from others on the issue, what they think about it, what it could be used for. It would help define the application domain (also called problem domain). > > One thing is to create something useful. Another thing is to create > > something useful as a _library_ component. As has been noted regarding > > application and library development, application development and library > > development is typically quite different. With an application, you typically > > have quite specific requirements. With a library component, however, it's > > about anticipating future use. Or making something general enough to be > > useful as a library component. > > Very true, but some libraries are useful simply because they're simply code that > people would write themselves over and over... only done in a better way. Yeah. Also, Björn Karlsson had an informal questionnaire on the list a while ago, about what people were using Boost for, and it turned out to be especially the simple components (not necessarily simple in implementation, by all means, but simple in concept) which were used, such as ref, bind, function objects, the smart pointers, etc. These are components which, as I mentioned, does one thing, and one thing well. That makes it easier to use/reuse these components in different contexts, as they are like building blocks. Of course "one thing" may be anything. In the case of MPL, it's a framework for metaprogramming, where each component does one thing. Thus, it provides a "language" for making things. > In the > current state of discussion, it sounds like something that I would definitely > use. I've implemented poor versions on the fly in the past... always more > specific than composite_format... One big use of special display > functions/operators is that you can call them from the debugger. If there was a > debug-time friendly version of composite object output functions... and all I > needed to do was #include a specific header, that would be absolutely fantastic! Aha. Good point. > > You may do this: > > > > for(MapList::const_iterator i=list.begin(); i!=list.end(); ++i) > > std::cout << '[' << i->first << ',' << i->second << "]\n"; > > > > Or you may do: > > > > std::cout << composite_format("[", "]", "\n") << list; > > > > The question is, is it worth it? > > > > Of course, having defaults, the latter may be reduced to: > > > > std::cout << list; > > I absolutely hate not being able to do this last one by default. Having a well > written default for this makes it all worth it for me! The for loop has no chance > of being evaluated properly in a debugger, but a debugger can likely call the << > operator with less difficulty. Right. > How easilly can a debugger print out an STL object? I know that gdb can call > functions that are defined in the code. For templated functions, this is probably > a major hassle. Could there be some way to enable a debugger to call a function > like this? If so, what's the best way to enable that without massive efforts from > the user? I guess it depends on the debugger. I've typically done such printing explicitly in the code, rather than invoking it in the debugger. > I also could imagine some way of adding hooks intended for calling from a debugger > to alter output behavior based on what the person debugging is interested in > Say for instance forcing the output of a specific type to be suppressed? > > I'm pulling at stings, but there has to be good stuff to add if we come up with > the right aspect to develop. I have never heard of a library designed for > evaluation of debug-time
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > Regarding this project. I've got doubts about the viability of it. Well, I'm glad you've given it a greater level of thought. I really like the idea of the composite_format, and probably should try to do the same :) > One thing is to create something useful. Another thing is to create > something useful as a _library_ component. As has been noted regarding > application and library development, application development and library > development is typically quite different. With an application, you typically > have quite specific requirements. With a library component, however, it's > about anticipating future use. Or making something general enough to be > useful as a library component. Very true, but some libraries are useful simply because they're simply code that people would write themselves over and over... only done in a better way. In the current state of discussion, it sounds like something that I would definitely use. I've implemented poor versions on the fly in the past... always more specific than composite_format... One big use of special display functions/operators is that you can call them from the debugger. If there was a debug-time friendly version of composite object output functions... and all I needed to do was #include a specific header, that would be absolutely fantastic! > I've thought a lot about this, these days, regarding the composite > operators. Trying to find the essential abstraction. Clearly, they are about > passing composite objects (such as arrays, standard containers, etc.) to a > stream, so that is the abstraction. This is also something which isn't > covered much in current libraries. The question is if there's enough > commonality in this abstraction, to warrant a library implementation. > > For the composite operators to be genuinely useful in a broader context, I > think it's important that they do one thing, and one thing well. > > The challenge is to make something general enough, yet reasonably easy to > use. Easy things should be easy, and hard things should be possible. > > My concern is, for example, for outputting a > std::vector >: > > typedef std::pair Map; > typedef std::vector MapList; > > MapList list; > > You may do this: > > for(MapList::const_iterator i=list.begin(); i!=list.end(); ++i) > std::cout << '[' << i->first << ',' << i->second << "]\n"; > > Or you may do: > > std::cout << composite_format("[", "]", "\n") << list; > > The question is, is it worth it? > > Of course, having defaults, the latter may be reduced to: > > std::cout << list; I absolutely hate not being able to do this last one by default. Having a well written default for this makes it all worth it for me! The for loop has no chance of being evaluated properly in a debugger, but a debugger can likely call the << operator with less difficulty. > It also comes back to the question of commonality and variability. > Currently, it uses static strings for start, end, and element delimiter. > Anything else, and you need to use something else. > > I was first thinking of generalising it to any string type (rather than > std::basic_string), but I've found that even that doesn't go far enough, if > you want to change it radically. I've then been thinking of the possibility > of passing a functor, instead, to the manipulator. The manipulator could > then invoke this functor for each element to be output. This would enable > things like listing element number in the output, by passing in an > appropriate functor for this. The current semantics might be catered for by > another functor, and overloaded constructors for this case may also be > provided for convenience. > > BGL is similar, in that graphs are also composite objects. It uses > "visitors", which are functors with multiple member functions (not just > overloaded operator()), which are called at specific points in an algorithm. > The same could be done with the composite operators, calling the functor at > start, end and for each element. > > However, as the algorithm in this case is just iterating over a sequence, > calling a functor or outputting each element, it's more or less the same as > a for-loop, or for_each. > > It's also a question of what design space we are targeting: Originally, > Vladimir Prus's suggestion was for something that could help with debug > output. It's a question whether or not this can be made general enough to be > useful beyond that, and if that is even desirable, concerning things like > usability. How easilly can a debugger print out an STL object? I know that gdb can call functions that are defined in the code. For templated functions, this is probably a major hassle. Could there be some way to enable a debugger to call a function like this? If so, what's the best way to enable that without massive efforts from the user? I also could imagine some way of adding hooks intended for calling from a debugger to alter output behavior based on what the person de
Re: [boost] Re: io operations for stl containers?
Regarding this project. I've got doubts about the viability of it. One thing is to create something useful. Another thing is to create something useful as a _library_ component. As has been noted regarding application and library development, application development and library development is typically quite different. With an application, you typically have quite specific requirements. With a library component, however, it's about anticipating future use. Or making something general enough to be useful as a library component. I've thought a lot about this, these days, regarding the composite operators. Trying to find the essential abstraction. Clearly, they are about passing composite objects (such as arrays, standard containers, etc.) to a stream, so that is the abstraction. This is also something which isn't covered much in current libraries. The question is if there's enough commonality in this abstraction, to warrant a library implementation. For the composite operators to be genuinely useful in a broader context, I think it's important that they do one thing, and one thing well. The challenge is to make something general enough, yet reasonably easy to use. Easy things should be easy, and hard things should be possible. My concern is, for example, for outputting a std::vector >: typedef std::pair Map; typedef std::vector MapList; MapList list; You may do this: for(MapList::const_iterator i=list.begin(); i!=list.end(); ++i) std::cout << '[' << i->first << ',' << i->second << "]\n"; Or you may do: std::cout << composite_format("[", "]", "\n") << list; The question is, is it worth it? Of course, having defaults, the latter may be reduced to: std::cout << list; It also comes back to the question of commonality and variability. Currently, it uses static strings for start, end, and element delimiter. Anything else, and you need to use something else. I was first thinking of generalising it to any string type (rather than std::basic_string), but I've found that even that doesn't go far enough, if you want to change it radically. I've then been thinking of the possibility of passing a functor, instead, to the manipulator. The manipulator could then invoke this functor for each element to be output. This would enable things like listing element number in the output, by passing in an appropriate functor for this. The current semantics might be catered for by another functor, and overloaded constructors for this case may also be provided for convenience. BGL is similar, in that graphs are also composite objects. It uses "visitors", which are functors with multiple member functions (not just overloaded operator()), which are called at specific points in an algorithm. The same could be done with the composite operators, calling the functor at start, end and for each element. However, as the algorithm in this case is just iterating over a sequence, calling a functor or outputting each element, it's more or less the same as a for-loop, or for_each. It's also a question of what design space we are targeting: Originally, Vladimir Prus's suggestion was for something that could help with debug output. It's a question whether or not this can be made general enough to be useful beyond that, and if that is even desirable, concerning things like usability. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Jason House wrote: > > > Terje Slettebø wrote: > > > > > Another possibility might be to have a sentry object, doing automatic state > > > saving and restoring in the constructor and destructor. In fact, there are > > > already such classes in Boost: Daryle Walker's I/O state savers, which fits > > > this situation like a glove. > > > > I think that I like your solution better :) putting it constructor/deconstructor > > does seem better. I can't even argue that it's more typing for multi-line > > expressions... > > Well, I know at least have more fuel to think about... > First of all, does your constructor take the stream as an argument? It would have to > in order to do state saving in the constructor... If so, that at least makes prevents > the following case (that probably needs special handling) > { > io_format<> var1(...); > std::cout << var1 << stuff; > std::cerr << var1 << more_stuff; > } > > My understanding is that the constructor would not perform state saving, but that it > is the call to << that has to perform the locking. Right. In the example I had, << performed the saving. In that case, it would have to check a save-flag in the destructor. One could also pass the stream to it in the constructor, as you say. > So what happens when multiple streams are used? That's no problem. The format is set for a specific stream (each stream has its own iword/pword for the type to be output). So for the free-standing saver, it would need to take the stream as a constructor argument. > what happens when you have 2 or more io_formats in the same function used on the same > stream? > example > { > io_format var1(...), var2(...); > std:: cout << var1 << stuff1; > std::cout << var2 << stuff2; > std::cout << var1 << stuff3; > std::cout << var2 << stuff4; > std::cout << io_format(...) << stuff5; > } /* deconstruct all 3 io_format's ... not necessarilly in the right order! */ This should work just fine. When the manipulator is used, it sets the format given by it. When a new manipulator is used, it changes the format to the new one. Also, the language ensures that the objects are destroyed in the reverse order of creation, so they will all be deleted after the last statement above. > Here, var1, var2, and the unnamed class from the last line in the function are all > being deconstructed at the same time. Some caution needs to occur here. Well, as this version of them just sets the format, and doesn't do anything in the destructor, their order of destruction doesn't matter for the output. > Is that what the state-saver class you referred to does already? That one does the restoring in the destructor. If we used the combined setter/saver/restorer I mentioned in the posting I just sent, them only the first of the above formats (var1), needed to save the format, to ensure that the format wasn't changed by the output statements. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > >From: "Jason House" <[EMAIL PROTECTED]> > > > I thought of one thing that might work reasonably well. > > > > > > How about making ++io_format< T > save the current format in a stack. > > > and having io_format< T>-- restore the previously queuued format > > > > > so, then something like > > > > > > > > std::cout << ++io_format("\n|","|\n","|")-- > > > > > << ++io_format > (&)[3][3]>("---","---","---")-- > > > > > << board << '\n'; > > > > > > would save and restore the formating for char(&)[3][3] and char(&)[3] and > > never stomp on anything else. > > > > In this case, it seems it saves and restores the format, before the format > > gets a chance to be used. In other words, the scope only covers the state > > saving, not the output. > > The idea was pre-increment and post-decrement... I wasn't sure if pre & post > operators work the same for classes as they do for primitive types. Well, you can define them like that, as well. However, even in that case, because of operator precedence, it will evaluate ++ and --, before <<, so it would save and restore the state, before outputting. > > std::cout << composite_save >() << composite_format(...) << v << > > '\n'; > > > > An alternative is a named temporary, such as: > > > > composite_save > sentry(stream); > > > > // Set format and do output > > I think that I like your solution better :) putting it constructor/deconstructor > does seem better. I can't even argue that it's more typing for multi-line > expressions... Come to think of it, we may get the best of both worlds. :) Since the format manipulator object also is a temporary, it can do the saving/restoring. :) You could then do e.g: std::cout << composite_format(...,true) << v; This saves the format, changes it, performs output, and restores the format in the destructor. Likewise: composite_format sentry(std::cout,...,true); // Save format, and set new format. Restore in destructor. // Do output std::cout << composite_format(...) << v; // Doesn't save/restore the format Alternatively, it could default to save. > When I originally started this, I said that it was the same complaint I have about > io_manip... It would be neat to have a replacement/wrapper boot library for > io_manip. I think the mentioned Boost I/O state savers would do that job well. That's exactly what they are for. Have you looked at them? Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Jason House wrote: > Terje Slettebø wrote: > > > Another possibility might be to have a sentry object, doing automatic state > > saving and restoring in the constructor and destructor. In fact, there are > > already such classes in Boost: Daryle Walker's I/O state savers, which fits > > this situation like a glove. > > > > I think that I like your solution better :) putting it constructor/deconstructor > does seem better. I can't even argue that it's more typing for multi-line > expressions... Well, I know at least have more fuel to think about... First of all, does your constructor take the stream as an argument? It would have to in order to do state saving in the constructor... If so, that at least makes prevents the following case (that probably needs special handling) { io_format<> var1(...); std::cout << var1 << stuff; std::cerr << var1 << more_stuff; } My understanding is that the constructor would not perform state saving, but that it is the call to << that has to perform the locking. So what happens when multiple streams are used? what happens when you have 2 or more io_formats in the same function used on the same stream? example { io_format var1(...), var2(...); std:: cout << var1 << stuff1; std::cout << var2 << stuff2; std::cout << var1 << stuff3; std::cout << var2 << stuff4; std::cout << io_format(...) << stuff5; } /* deconstruct all 3 io_format's ... not necessarilly in the right order! */ Here, var1, var2, and the unnamed class from the last line in the function are all being deconstructed at the same time. Some caution needs to occur here. Is that what the state-saver class you referred to does already? ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > >From: "Jason House" <[EMAIL PROTECTED]> > > I thought of one thing that might work reasonably well. > > > > How about making ++io_format< T > save the current format in a stack. > > and having io_format< T>-- restore the previously queuued format > > I've thought of the exact same thing. :) Not how the syntax for it would be, > but when I was thinking of this, it suddenly occurred to me: State savers! > > This essentially creates a scope in the state space. As you say, you may > then read the currently set format, and restore it afterwards. The > restoration is important, and there are issues such as exception safety. > > > so, then something like > > > > > > std::cout << ++io_format("\n|","|\n","|")-- > > > > << ++io_format (&)[3][3]>("---","---","---")-- > > > > << board << '\n'; > > > > would save and restore the formating for char(&)[3][3] and char(&)[3] and > never > > stomp on anything else. > > In this case, it seems it saves and restores the format, before the format > gets a chance to be used. In other words, the scope only covers the state > saving, not the output. The idea was pre-increment and post-decrement... I wasn't sure if pre & post operators work the same for classes as they do for primitive types. > Another possibility might be to have a sentry object, doing automatic state > saving and restoring in the constructor and destructor. In fact, there are > already such classes in Boost: Daryle Walker's I/O state savers, which fits > this situation like a glove. > > In your original posting, you had this example: > > >For instance, if you have a type > >map > > > >and custom_object's stream output uses io_format >, then > >you are going to run into trouble if it wants a different formatting. > > Such a custom object may then have something like the following in its > stream output: > > boost::io::ios_pword_saver(stream,index); > > // Set stream state, and do output. > > That's all. :) > > This also ensures that the state is restored properly, even in the presence > of exceptions, something the ++/-- way won't do. Of course, this requires > the pword-index, so one might make the interface more user friendly, and fit > the rest, for example by making the state saver a manipulator, itself. > > As I understand, the lifetime of a temporary object extends until the end of > the full expression it's used in, so the following should be well-defined: > > std::vector v; > > std::cout << composite_save >() << composite_format(...) << v << > '\n'; > > This saves the format at the start, and restores it at the end. > > An alternative is a named temporary, such as: > > composite_save > sentry(stream); > > // Set format and do output I think that I like your solution better :) putting it constructor/deconstructor does seem better. I can't even argue that it's more typing for multi-line expressions... When I originally started this, I said that it was the same complaint I have about io_manip... It would be neat to have a replacement/wrapper boot library for io_manip. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Larry Evans" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > >>From: "Vladimir Prus" <[EMAIL PROTECTED]> > > > >>Terje Slettebø wrote: > > [snip] > > > > std::cout << io_format("\n|","|\n","|") > > << io_format("---","---","---") > > << board << '\n'; > > } > > > > we get: > > > > --- > > |O|X|O| > > --- > > |X|X|O| > > --- > > |O|O|X| > > --- > > I've used marg_ostream to format output for containers; however, > it only used something that changed the margin. I had to > use an ostream<< for the particular composite to get it to work. > However, being able to adjust the margin seems useful for > formating most code. Looking at the code might give you > some more ideas about your io_format. Unfortunately, marg_ostream > requires wrapping the cout in a marg_ostream. > > Anyhow, the code is in boost files in shared_cyclic_ptr/shared_cyclic_ptr.zip > in boost/col_io directory. Basically, marg_ostream++ increments the > margin and marg_ostream-- decrements the margin. You can also specify > what's in the margin. This was used to show the nesting in a fortran > program in a parallelizing compiler. Thanks for the tip. I'll look into it. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > > It should handle maps and pairs > > > reasonably well. I think that I have the same complaints about this as > > > io_manip > > > > > > The saving of information to the stream means that you can affect all > > > future output... > > > > > > For instance, if you have a type > > > map > > > > > > > and custom_object's stream output uses io_format >, then > > > you are going to run into trouble if it wants a different formatting. > > > > Right. That's a consequence of this. As you say too, I don't know any > > obvious alternatives, though. > > I thought of one thing that might work reasonably well. > > How about making ++io_format< T > save the current format in a stack. > and having io_format< T>-- restore the previously queuued format I've thought of the exact same thing. :) Not how the syntax for it would be, but when I was thinking of this, it suddenly occurred to me: State savers! This essentially creates a scope in the state space. As you say, you may then read the currently set format, and restore it afterwards. The restoration is important, and there are issues such as exception safety. > so, then something like > > > > std::cout << ++io_format("\n|","|\n","|")-- > > > << ++io_format("---","---","---")-- > > > << board << '\n'; > > would save and restore the formating for char(&)[3][3] and char(&)[3] and never > stomp on anything else. In this case, it seems it saves and restores the format, before the format gets a chance to be used. In other words, the scope only covers the state saving, not the output. Another possibility might be to have a sentry object, doing automatic state saving and restoring in the constructor and destructor. In fact, there are already such classes in Boost: Daryle Walker's I/O state savers, which fits this situation like a glove. In your original posting, you had this example: >For instance, if you have a type >map > >and custom_object's stream output uses io_format >, then >you are going to run into trouble if it wants a different formatting. Such a custom object may then have something like the following in its stream output: boost::io::ios_pword_saver(stream,index); // Set stream state, and do output. That's all. :) This also ensures that the state is restored properly, even in the presence of exceptions, something the ++/-- way won't do. Of course, this requires the pword-index, so one might make the interface more user friendly, and fit the rest, for example by making the state saver a manipulator, itself. As I understand, the lifetime of a temporary object extends until the end of the full expression it's used in, so the following should be well-defined: std::vector v; std::cout << composite_save >() << composite_format(...) << v << '\n'; This saves the format at the start, and restores it at the end. An alternative is a named temporary, such as: composite_save > sentry(stream); // Set format and do output > The net effect is that you can optionally add the extra few characters and prevent > stomping on other code that is displaying your class. Exactly. :) I feel fortunate to have so many competent people around me. This certainly gives library building a boost. :) Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > > It should handle maps and pairs > > reasonably well. I think that I have the same complaints about this as > > io_manip > > > > The saving of information to the stream means that you can affect all > > future output... > > > > For instance, if you have a type > > map > > > > > and custom_object's stream output uses io_format >, then > > you are going to run into trouble if it wants a different formatting. > > Right. That's a consequence of this. As you say too, I don't know any > obvious alternatives, though. > I thought of one thing that might work reasonably well. How about making ++io_format< T > save the current format in a stack. and having io_format< T>-- restore the previously queuued format so, then something like > > std::cout << ++io_format("\n|","|\n","|")-- > > << ++io_format("---","---","---")-- > > << board << '\n'; would save and restore the formating for char(&)[3][3] and char(&)[3] and never stomp on anything else. The net effect is that you can optionally add the extra few characters and prevent stomping on other code that is displaying your class. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Terje Slettebø" <[EMAIL PROTECTED]> > const int array[3]; > > std::cout << array; > > MSVC 7 - C > Intel C++ 7 - C > g++ 3.2 - C > > const char array[3]; > > std::cout << array; > > MSVC 7- A (S or C) > Intel C++ 7 - C > g++ 3.2 - C > > std::cout << "Test"; > > MSVC 7 - A (S or C) > Intel 7 - C > g++ 3.2 - A (S or C) > > In order to allow string literals to be used, without ambiguity or the wrong > operator being selected, it seems that one needs to overload operator<< on > something else than T(&)[N]. T[N] isn't an option, either, as this is the > same as overloading on T *, which means it isn't able to deduce N. > > This quandary may be solved by wrapping arrays in an object, which then is > passed to the overloaded operator<<. For example: > > std::cout << wrap_array(array); I found that boost::ref works for this, as well, so you may use: char array[3[[3][3]; std::cout << array; // Overloading for this gives wrong handling of string literals, on all compilers. std::cout << cref(array); // Ok For example: void array3D_test() { char boards[3][3][3]= { { {'X','O','X'}, {'O','X','O'}, {'X','O','X'} }, { {'X','X','X'}, {'X','O','X'}, {'X','X','X'} }, { {'O','X','O'}, {'X','X','X'}, {'O','X','O'} } }; std::cout << composite_format >("\n|","|\n","|") << composite_format >("---","---","---") << composite_format >("--- Boards ---\n\n","\n\n--- Boards ---","\n\n") << boost::cref(boards) << '\n'; } Output: --- Boards --- --- |X|O|X| --- |O|X|O| --- |X|O|X| --- --- |X|X|X| --- |X|O|X| --- |X|X|X| --- --- |O|X|O| --- |X|X|X| --- |O|X|O| --- --- Boards --- I'll work on a version that works with this. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Paul A. Bristow" <[EMAIL PROTECTED]> > This looks really neat - and potentially very useful. Thanks. :) > Sadly, array is one of the most interesting cases - so I'm sure I won't be the > only one 'watching this space'. I've looked more into it, and it seems this is a problem not just for MSVC, but a problem with the current way of doing it, overloading operator<< for T(&)[N], sinch string literals has the type "const char[N]", as well... With overloaded operator<< for T(&)[N], and using "std::cout << "Test" ", g++ gives an ambiguity error, while on Intel C++, it selects the composite overload, resulting in funny output: It tries to output the null-terminator, as well, not knowing that for character strings, this is a string terminator. Besides, it can't really know if the user meant to send a character string, or a non-null-terminated character array. It seems the differences is down to subtle implementation differences. Here are the results, when an overloaded operator<< with T[N] is defined (S - string-literal operator, C - composite operator (T(&)[N]), A - ambiguous): const int array[3]; std::cout << array; MSVC 7 - C Intel C++ 7 - C g++ 3.2 - C const char array[3]; std::cout << array; MSVC 7- A (S or C) Intel C++ 7 - C g++ 3.2 - C std::cout << "Test"; MSVC 7 - A (S or C) Intel 7 - C g++ 3.2 - A (S or C) In order to allow string literals to be used, without ambiguity or the wrong operator being selected, it seems that one needs to overload operator<< on something else than T(&)[N]. T[N] isn't an option, either, as this is the same as overloading on T *, which means it isn't able to deduce N. This quandary may be solved by wrapping arrays in an object, which then is passed to the overloaded operator<<. For example: std::cout << wrap_array(array); Comments/suggestions? > PS composite_format is a bit long, but I can't suggest better. I know, but I don't know any better, either. I see that Volodya suggests composite_io in another posting. That's another possibility. Anyway, I guess what's most important is to get the functionality in place. A default system may make it easier, as well. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Terje Slettebø wrote: By the way, just for fun. Adding the following output operator for arrays, to the header I gave in the previous posting: --- |O|X|O| --- |X|X|O| --- |O|O|X| --- "Shall we play a game?" :) Sure thing :-) I guess you maybe got the "War Games" reference? :) Don't know what this reference is, but played that game in school. 2. I think that we better have separate headers for stl containers, like suggested in my original email (, etc). That's because I'd like to output maps, but would not like to include when I need to output a vector. Heh, just before I got this posting, I had added the following comment in the header: [...] We're in total agreement until now. I'll get back to your other comments, I just need to look more into how it might be done. Maybe you know a better solution already, but thinking about per-conainer format is arrive to: We basically need the following (note that "..." are no metacharacters) template class container> class basic_composite_io { int get_pword_index(); } template int basic_composite_io >::get_pword_index() { static int i = ios_base::xalloc(); return i; } Since we can specialize on template name, we have to fake that: template int basic_composite_io >::get_pword_index() { static int i = get_vector_pword_index(); return i; } Why can't we afford to create a function for each supported container, make it call xalloc, and return that value. Not very nice, but works. Another alternative is to create custom 'xalloc' which takes a string, and does not allocate new index if an index for that string is already allocated. template int basic_composite_io >::get_pword_index() { static int i = xalloc("std::vector"); return i; } Would this be sufficient? - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: io operations for stl containers?
This looks really neat - and potentially very useful. Sadly, array is one of the most interesting cases - so I'm sure I won't be the only one 'watching this space'. Thanks Paul PS composite_format is a bit long, but I can't suggest better. Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 Mobile mailto:[EMAIL PROTECTED] mailto:[EMAIL PROTECTED] > Looking at the error messages, and from what I've heard, it may be that it > has problems with template friends (which is what the operator<< is). If > that's the case, the workaround should be very easy - making it a > free-function template. > > I did that, now, and it works. :) > > At least the vector_pair_test(). The array2D_test() uses a little fancy > code, such as passing the type reference to array as a template parameter, > and it seems MSVC 7.0 has some problems with this. Anyway, that was just to > demonstrate usage with built-in types, as well, such as arrays. I'll look > into it. > > There wasn't really any need for it to be a friend function, as it didn't > access any private parts. It was just defined inside the class for > convenience. > > I've also tested it on Intel C++ 7.0 in strict mode and g++ 3.2, so the code > should be conformant, at least. > > Thanks for the report. I hadn't yet got around to do more portability > testing, but intend to do that, including writing more tests for it. I've > updated the version at Yahoo Groups with the above changes. > > > Regards, > > Terje > > ___ > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost > ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Jason House" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > and given this: > > > > int main() > > { > > char board[3][3]= > > { > > {'O','X','O'}, > > {'X','X','O'}, > > {'O','O','X'} > > }; > > > > std::cout << io_format("\n|","|\n","|") > > << io_format("---","---","---") > > << board << '\n'; > > } > > > > we get: > > > > --- > > |O|X|O| > > --- > > |X|X|O| > > --- > > |O|O|X| > > --- > > Hey, that's pretty cool. I'm glad to see the ability to format items > inside of a container as well. I'm glad you like. :) Yes, it applies operator<< recursively, using overloading, and any format settings for the given type, so for the outer array, it matches the second format above, and for the inner it matches the first one. > It should handle maps and pairs > reasonably well. I think that I have the same complaints about this as > io_manip > > The saving of information to the stream means that you can affect all > future output... > > For instance, if you have a type > map > > > and custom_object's stream output uses io_format >, then > you are going to run into trouble if it wants a different formatting. Right. That's a consequence of this. As you say too, I don't know any obvious alternatives, though. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Paul A. Bristow" <[EMAIL PROTECTED]> > This looks most useful - potentionally :-( > > Alas the two files, test and composite_stream_operators.hpp > > http://groups.yahoo.com/group/boost/files/composite_stream_operators/). > > won't compile on MSVC 7.0. > > test_composite_format.cpp > test_composite_format.cpp(43) : error C2679: binary '<<' : no operator found > which takes a right-hand operand of type 'composite_format' (or there is no > acceptable conversion) > with > [ > T=char (&)[3] > ] > > and similarly for T=Map > > Is the cause/workaround obvious? Looking at the error messages, and from what I've heard, it may be that it has problems with template friends (which is what the operator<< is). If that's the case, the workaround should be very easy - making it a free-function template. I did that, now, and it works. :) At least the vector_pair_test(). The array2D_test() uses a little fancy code, such as passing the type reference to array as a template parameter, and it seems MSVC 7.0 has some problems with this. Anyway, that was just to demonstrate usage with built-in types, as well, such as arrays. I'll look into it. There wasn't really any need for it to be a friend function, as it didn't access any private parts. It was just defined inside the class for convenience. I've also tested it on Intel C++ 7.0 in strict mode and g++ 3.2, so the code should be conformant, at least. Thanks for the report. I hadn't yet got around to do more portability testing, but intend to do that, including writing more tests for it. I've updated the version at Yahoo Groups with the above changes. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
Terje Slettebø wrote: From: "Vladimir Prus" <[EMAIL PROTECTED]> Terje Slettebø wrote: [snip] std::cout << io_format("\n|","|\n","|") << io_format("---","---","---") << board << '\n'; } we get: --- |O|X|O| --- |X|X|O| --- |O|O|X| --- I've used marg_ostream to format output for containers; however, it only used something that changed the margin. I had to use an ostream<< for the particular composite to get it to work. However, being able to adjust the margin seems useful for formating most code. Looking at the code might give you some more ideas about your io_format. Unfortunately, marg_ostream requires wrapping the cout in a marg_ostream. Anyhow, the code is in boost files in shared_cyclic_ptr/shared_cyclic_ptr.zip in boost/col_io directory. Basically, marg_ostream++ increments the margin and marg_ostream-- decrements the margin. You can also specify what's in the margin. This was used to show the nesting in a fortran program in a parallelizing compiler. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: > and given this: > > int main() > { > char board[3][3]= > { > {'O','X','O'}, > {'X','X','O'}, > {'O','O','X'} > }; > > std::cout << io_format("\n|","|\n","|") > << io_format("---","---","---") > << board << '\n'; > } > > we get: > > --- > |O|X|O| > --- > |X|X|O| > --- > |O|O|X| > --- Hey, that's pretty cool. I'm glad to see the ability to format items inside of a container as well. It should handle maps and pairs reasonably well. I think that I have the same complaints about this as io_manip The saving of information to the stream means that you can affect all future output... For instance, if you have a type map > and custom_object's stream output uses io_format >, then you are going to run into trouble if it wants a different formatting. I don't know the right way to solve that problem though. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: io operations for stl containers?
This looks most useful - potentionally :-( Alas the two files, test and composite_stream_operators.hpp http://groups.yahoo.com/group/boost/files/composite_stream_operators/). won't compile on MSVC 7.0. test_composite_format.cpp test_composite_format.cpp(43) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=char (&)[3] ] and similarly for T=Map Is the cause/workaround obvious? Thanks Paul Full messages: test_composite_format.cpp test_composite_format.cpp(29) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=Map ] j:\Cpp\composite_format\composite_stream_operators.hpp(42) : warning C4933: 'std::basic_ostream &operator <<(std::basic_ostream &,const basic_composite_format &)' and 'std::basic_ostream &operator <<(std::basic_ostream &,const basic_composite_format &)' only differ by top-level CV-qualifiers in their arguments. This usage is deprecated and may be an error in the future with [ CharType=char, T=char (&)[3] ] j:\Cpp\composite_format\composite_stream_operators.hpp(42) : see declaration of 'operator`<<'' j:\Cpp\composite_format\composite_stream_operators.hpp(42) : see declaration of 'operator`<<'' j:\Cpp\composite_format\composite_stream_operators.hpp(83) : see reference to class template instantiation 'basic_composite_format' being compiled with [ CharType=char, T=char (&)[3] ] test_composite_format.cpp(42) : see reference to class template instantiation 'composite_format' being compiled with [ T=char (&)[3] ] test_composite_format.cpp(43) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=char (&)[3] ] j:\Cpp\composite_format\composite_stream_operators.hpp(42) : warning C4933: 'std::basic_ostream &operator <<(std::basic_ostream &,const basic_composite_format &)' and 'std::basic_ostream &operator <<(std::basic_ostream &,const basic_composite_format &)' only differ by top-level CV-qualifiers in their arguments. This usage is deprecated and may be an error in the future with [ CharType=char, T=char (&)[3][3] ] j:\Cpp\composite_format\composite_stream_operators.hpp(42) : see declaration of 'operator`<<'' j:\Cpp\composite_format\composite_stream_operators.hpp(42) : see declaration of 'operator`<<'' j:\Cpp\composite_format\composite_stream_operators.hpp(83) : see reference to class template instantiation 'basic_composite_format' being compiled with [ CharType=char, T=char (&)[3][3] ] test_composite_format.cpp(43) : see reference to class template instantiation 'composite_format' being compiled with [ T=char (&)[3][3] ] Build log was saved at "file://j:\Cpp\composite_format\Debug\BuildLog.htm" composite_format - 2 error(s), 2 warning(s) and for simpler tests like a pair, vector ... test_composite_format.cpp(25) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=std::pair ] test_composite_format.cpp(36) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=std::vector> ] test_composite_format.cpp(37) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'composite_format' (or there is no acceptable conversion) with [ T=std::vector> ] > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED]]On Behalf Of Terje Slettebø > Sent: Tuesday, February 04, 2003 1:46 PM > To: Boost mailing list > Subject: Re: [boost] Re: io operations for stl containers? > > > >From: "Vladimir Prus" <[EMAIL PROTECTED]> > > > Terje Slettebø wrote: > > > > > Incidentally, I've just made a version that do
Re: [boost] Re: io operations for stl containers?
>From: "Vladimir Prus" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > There are also some other issues: The current version assumes basic_string > > for the delimiters. I've found it hard to let it take an arbitrary string > > type, as the format-object (which the manipulator, basic_composite_format, > > doubles as) stores a format parameterised on type to output and character > > type. The latter is so that if multiple streams with different character > > types are used, they should not use the same format-object.. > > Is assuming basic_string really a problem? No, not really. I was just thinking of generality. However, as it is, it needs the character type, anyway. > > By the way, just for fun. Adding the following output operator for arrays, > > to the header I gave in the previous posting: > > > --- > > |O|X|O| > > --- > > |X|X|O| > > --- > > |O|O|X| > > --- > > > > "Shall we play a game?" :) > > Sure thing :-) I guess you maybe got the "War Games" reference? :) > > I've uploaded the new version here > > (http://groups.yahoo.com/group/boost/files/composite_stream_operators/). > > There are two more points: > 1. Could you put this to the sandbox, too. Yahoogroups is less convenient. Sure. :) > 2. I think that we better have separate headers for stl containers, like > suggested in my original email (, etc). That's > because I'd like to output maps, but would not like to include when > I need to output a vector. Heh, just before I got this posting, I had added the following comment in the header: /// // The following are just a few examples of output operators, for some of the // containers and types in the standard library. These could well be separated // in other files. That would also reduce the number of includes. /// :) Will do. I'll get back to your other comments, I just need to look more into how it might be done. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Beman Dawes wrote: At 03:22 AM 2/4/2003, Vladimir Prus wrote: >Terje Slettebø wrote: >... Have you looked at Jen Maurer's persistence library? It was an elegant design and quite good at handling the issues you are discussing, IIRC. It is still in CVS under the branch "persistence-initial". Beman, that's not presicely what I needed. Using persistence to output a single vector is still very verbose, compared with operator<<. shift_writer w(cout); save(v, w); I've always been sorry Jens lost interest in carrying it forward to formal review. Me too. - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: I've some concerns, though: 1. Are "default" breaces/separators possible? I'd rather not use io_format every time I had to output a vector. Good point. As it is now, it just defaults to empty strings for the separators. Any idea how to specify such a default? If it's specified in the header, it may be hard to select one that is sensible for all people. I've no problems with hardcoding. But if you want, you might user static members of the same class which provides pword() index via another static method. And there should be default default. 2. Is that good idea to set brace style on vector and vector separately? It would increase pword() array, and not sure if this will benefit us much. Are nested containers the primary motivation? Another good point. I guess there isn't any point in separate formats for different element types, no. The way it works now is that it instantiates an basic_composite_format (name changed from basic_io_format), containing a static function with a static xalloc() index, for each type to be output. Thus, it's parameterised on a type, not a partially specified type. Yes, I've see that too. I'll look into this, as well. Partial specialisation, inheriting from a less-parameterised base comes to mind. Hmm... I bet you'd need template template parameters for that. template class container> class basic_composite_format { }; Alas, this is not very allocator-friendly :-( There are also some other issues: The current version assumes basic_string for the delimiters. I've found it hard to let it take an arbitrary string type, as the format-object (which the manipulator, basic_composite_format, doubles as) stores a format parameterised on type to output and character type. The latter is so that if multiple streams with different character types are used, they should not use the same format-object.. Is assuming basic_string really a problem? By the way, just for fun. Adding the following output operator for arrays, to the header I gave in the previous posting: int main() { char board[3][3]= { {'O','X','O'}, {'X','X','O'}, {'O','O','X'} }; std::cout << io_format("\n|","|\n","|") << io_format("---","---","---") << board << '\n'; } we get: --- |O|X|O| --- |X|X|O| --- |O|O|X| --- "Shall we play a game?" :) Sure thing :-) The names and interface is just chosen tentatively, and I'm open to suggestions for better names. I changed the "*io_format" names to "*composite_format", as it reflects better what it does, and reduces the chance for name collision. I didn't want to call it container_format, or something like that, as it's not restricted to containers, but may output any composite object, given suitably defined output operators (such as std::vector, std::pair, arrays, etc.) I like the names. Thanks for the feedback. You're welcome. After all, it's me who's bored to use custom code ;-) I've uploaded the new version here (http://groups.yahoo.com/group/boost/files/composite_stream_operators/). There are two more points: 1. Could you put this to the sandbox, too. Yahoogroups is less convenient. 2. I think that we better have separate headers for stl containers, like suggested in my original email (, etc). That's because I'd like to output maps, but would not like to include when I need to output a vector. What do you think? - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Vladimir Prus" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > > > Incidentally, I've just made a version that does exactly this. :) I've > > attached it, including a test, with this posting. > > I've take a look and I like it -- quite lean and does the work. Thanks. :) > I've some concerns, though: > > 1. Are "default" breaces/separators possible? I'd rather not use > io_format every time I had to output a vector. Good point. As it is now, it just defaults to empty strings for the separators. Any idea how to specify such a default? If it's specified in the header, it may be hard to select one that is sensible for all people. > 2. Is that good idea to set brace style on vector and vector > separately? It would increase pword() array, and not sure if this will > benefit us much. Are nested containers the primary motivation? Another good point. I guess there isn't any point in separate formats for different element types, no. The way it works now is that it instantiates an basic_composite_format (name changed from basic_io_format), containing a static function with a static xalloc() index, for each type to be output. Thus, it's parameterised on a type, not a partially specified type. I'll look into this, as well. Partial specialisation, inheriting from a less-parameterised base comes to mind. There are also some other issues: The current version assumes basic_string for the delimiters. I've found it hard to let it take an arbitrary string type, as the format-object (which the manipulator, basic_composite_format, doubles as) stores a format parameterised on type to output and character type. The latter is so that if multiple streams with different character types are used, they should not use the same format-object.. This means that one must know the character type of the delimiter strings, in order to parameterise the format object correctly. That's why basic_string is used, as you then get access to the character type. By the way, just for fun. Adding the following output operator for arrays, to the header I gave in the previous posting: /// // operator<<(stream,T[N]) /// template std::basic_ostream &operator<< (std::basic_ostream &stream,T (&array)[N]) { typedef basic_io_format format_type; const format_type &format=format_type::format(stream); stream << format.start << array[0]; for(std::size_t i=1;i!=N;++i) stream << format.delimiter << array[i]; stream << format.end; return stream; } and given this: int main() { char board[3][3]= { {'O','X','O'}, {'X','X','O'}, {'O','O','X'} }; std::cout << io_format("\n|","|\n","|") << io_format("---","---","---") << board << '\n'; } we get: --- |O|X|O| --- |X|X|O| --- |O|O|X| --- "Shall we play a game?" :) By the way, in the first posting, I figured you knew about stream iterators, so I was a little puzzled, but then it turned out I had just misunderstood what you meant. Reading it more carefully later, I saw that you did mention stream operators. The names and interface is just chosen tentatively, and I'm open to suggestions for better names. I changed the "*io_format" names to "*composite_format", as it reflects better what it does, and reduces the chance for name collision. I didn't want to call it container_format, or something like that, as it's not restricted to containers, but may output any composite object, given suitably defined output operators (such as std::vector, std::pair, arrays, etc.) Thanks for the feedback. I've uploaded the new version here (http://groups.yahoo.com/group/boost/files/composite_stream_operators/). Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: This example should one case where manipulators are desirable: vector< vector > v; cout << v ; Here, each nested vector better go on a separate line. I suggest: cout << multiline << v; where "multiline" manipulator causes each element of the next output container to go on separate line. The above io_format<>'s are intended to be manipulators. You could get this manipulator with: io_format >("\n","","") multiline; You could also make it so that this manipulator set the format for any container, but in cases where you have arbitrary deep nesting of containers (like in Peter Dimov's posting), it may be better to set the format on a per-type basis. I think that when more that double nesting is involed you have problems anyway. Incidentally, I've just made a version that does exactly this. :) I've attached it, including a test, with this posting. I've take a look and I like it -- quite lean and does the work. I've some concerns, though: 1. Are "default" breaces/separators possible? I'd rather not use io_format every time I had to output a vector. 2. Is that good idea to set brace style on vector and vector separately? It would increase pword() array, and not sure if this will benefit us much. Are nested containers the primary motivation? - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: io operations for stl containers?
>From: "Vladimir Prus" <[EMAIL PROTECTED]> > Terje Slettebø wrote: > >>From: "Vladimir Prus" <[EMAIL PROTECTED]> > > > >>after having to output std::vector to stream again and again using custom > >>solution, I started to wonder why we don't have a solution in boost. > >>Does it makes sense to include operators<< for vectors, sets, etc? > >> > >>I was thinking about > >> > >> > >> > > > You can do this quite well using the standard library and stream iterator > > adapters. This may do both of your approaches above. For example: > > I certainly know that. I guessed you might. However, the solution seemed like a good match to your question, given that you didn't give any code example of its use. You mentioned outputting a vector to a stream, using custom separators, and that's what this does. > > std::cout << "Print vector\n"; > > std::copy(list.begin(),list.end(),Out(std::cout,"\n")); > > And I don't like it in the least. Compared with > > std::cout << "new path is " << v << "\n"; I understand what you mean now. Regards, Terje ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Al Stevens who writes the C++ column for "Doctor Dobbs Journal" put out a persistent template library for C++ containers some time back. It is probably on the DDJ web site, although I haven't looked there recently. You might want to check that out and see what he did. I will readily admit I have not had the need to persist container data in my daily programming but I can understand others having that need. "Vladimir Prus" <[EMAIL PROTECTED]> wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... > > Hi, > > after having to output std::vector to stream again and again using custom > solution, I started to wonder why we don't have a solution in boost. > Does it makes sense to include operators<< for vectors, sets, etc? > > I was thinking about > > > > > and so on. There are basically two approaches: > > 1. Operators use fixed format: bracked list with commas between values for > vector, for example. > 2. Manipulators are provided to set brackets and separators. > > I had implemented the second approach some time ago, but it turned out that > was overkill. So, 1) looks better now. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: io operations for stl containers?
Terje Slettebø wrote: From: "Vladimir Prus" <[EMAIL PROTECTED]> after having to output std::vector to stream again and again using custom solution, I started to wonder why we don't have a solution in boost. Does it makes sense to include operators<< for vectors, sets, etc? I was thinking about You can do this quite well using the standard library and stream iterator adapters. This may do both of your approaches above. For example: I certainly know that. std::cout << "Print vector\n"; std::copy(list.begin(),list.end(),Out(std::cout,"\n")); And I don't like it in the least. Compared with std::cout << "new path is " << v << "\n"; the use of std::copy is way too verbose. BTW, you can't output std::pair that way. - Volodya ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost