
Johan RĂ¥de wrote:
2) I'm not completely sure about the "legacy" flag: shouldn't the facet just read in everything that it recognises by default? Or maybe we should flip the meanings and "legacy" should become "strict_read" or "nolegacy" or something - I'm not that keen on those names, but Boosters can usually come up with something snappy when asked :-)
There are cases where the legacy flag could change the meaning of a file. For instance, if you set the legacy flag, and parse the string "1#2", then "1#" will be interpreted as the beginning of "1#INF" or some other Visual Studio nonsense. Once the parser gets to '2', it will realize its mistake, but when you read using stream iterators it is impossible to backtrack, so the parser will set the failbit of the stream.
So the legacy flag can be a little dangerous. This should of course be pointed out in the docs.
Ah, I see, in that case it's probably best to leave as is, and add an "admonishment" to the docs to point this out.
4) I think the flags are useful, but would be a lot nicer as iostream manipulators - although I accept this may not work with lexical_cast :-(
BTW what was the issue that would require separate file compilation for manipulators?
It is about four years since last time I defined my own manipulators, but this is how I remember it:
When you define a manipulator you need to store some state information with the stream. Streams contain an integer array that should be used for that purpose. The nonfinite_num_facets would need to reserve a position in those arrays. That is done by calling std::xalloc, exactly once, and storing the returned integer value in a global integer variable. You must make sure that there is exactly one instance of that variable. If you pass stream objects between different DLL's, then you must make sure that all the DLL's share the same instance of that variable. Can that be guaranteed without having a cpp file, and compiling that file as a DLL that is used by the other DLL's?
This is tricky, the usual way would be to use boost::call_once: template <bool dummy> struct iostream_data { private: static int& get_iword_index() { static int index; return index; } static void init() { get_iword_index() = std::ios_base::xalloc(); } public: static void index() { static boost::once_flag f = BOOST_ONCE_INIT; boost::call_once(&iostream_data<dummy>::init, f); return get_iword_index(); } }; Then the manipulator can use iostream_data<true>::index() to obtain the index of iword it wants to use. The problem as you correctly point out is with DLL's: I'm fairly sure that on Unix (or Linux anyway) the shared library loader will resolve duplicate symbols so that just one is active in the program - that way only one instance of iostream_data<dummy> will be active and everything should work OK. On Windows though you could end up with separate instances of iostream_data<dummy> in each dll, which would be bad news if you expect to pass iostreams between them :-( The only - somewhat inelegant - solution I can think of is to define a pair of macros to import/export iostream_data<dummy> so users can control it's instantiation. Cheers, John.