This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: notes on _M_fill, non-required facets (fwd)


Benjamin Kosnik wrote:
> Subject: notes on _M_fill, non-required facets
> 
> 1) How should the library deal with instantiations of facets that are
> not required? I'm starting to be convinced that the sanest behavior is
> to compile facets for user-defined types, but not necessarily provide
> linkage. 
> 
> I see this as an implementation issue. The standard is unambiguous as to
> what types are standard (char, wchar_t) and what facet instantiations
> are required.
> See 22.1.1.1.1, sections two and four. 
> 
> Non-required instantiations, say unsigned char or unsigned short, have
> implementation-defined behavior.
> 
> What does ctype<unsigned short> mean?
> 
> I can make some guesses, but I suspect a wide variety of interpretations
> as to the expected behavior of this class.
> 
> If the library provides definitions for ctype<unsigned short>, and
> these definitions are not what is expected or at all useful, then how
> does the end user work around it? Hmmm. Tricky: use derivation of the
> generic ctype facet and provide definitions of the virtual members? That
> would work. Any other way? Perhaps you could play clever linker tricks,
> but that's less interesting, more fragile, and too much work.
> 
> If the library doesn't provide definitions for ctype<unsigned short>,
> what happens? I'd expect the code to compile, yet all the virtual member
> functions to be undefined at link-time, cluing the end-user into the
> limitations of the implementation. At this point, I'd expect the
> end-user to make a .cc file, include <locale>, declare a ctype
> specialization, and provide member function definitions for the
> specialized type. This would work as the definitions for the generic
> member functions in question haven't been seen (because they don't
> exist.) Note that derivation is still an option here.
> 
> I believe not providing the definitions is the best solution, giving the
> end user the most options, but am interested to see what others think.
> Perhaps I'm not seeing an element of this correctly, and if so I'd
> appreciate clarification.

Where standard conformance is concerned, explicit user specializations
instantiated on standard types (e.g. ctype<unsigned char>) are illegal.

(That does allow an implementation to define it, as an extension.)

Further, the standard does not require an implementation to provide 
definitions -- implicit specializations -- of them.  Certainly no 
standard locales contain any, in any case.

The standard only permits explicit specializations on user-defined types, 
such as std::ctype<My_char>.  We should concentrate our attention on 
support for pure user types.

Any stream operating on such types needs a locale explicitly populated 
with all the facets it will use.  The standard is pretty clear about 
which facets are needed by which operations.
 
> 2) How, and when, should iostreams report errors with missing facets? 
> 
> Graceful error recovery should be prefered over falling down completely.
> I've not yet reviewed the bug report in question, so I offer this just
> as background:
> 
> In general, formatted input and output happens through the numeric
> facets in a way that implies the use of use_facet. As such, if a stream
> is instantiated and expects to use member functions of facets obtained
> from a use_facet call that would fail, then bad_cast should be thrown:
> see 22.1.2.
> 
> In terms of initialization of streambufs et al, I think no errors should
> be reported until the facet's member functions are explicitly called or
> required: at that point, I think a thrown bad_cast is what is required.
> There might be some kinks in the current code about this, and without a
> doubt some kind of consistent behavior should be expected.

There's one kink in the plan.  

As I recall, iostream members and operators are not supposed to let
exceptions go by. I.e., upon receiving an exception from an underlying
function (such as a locale or facet operation) they are, IIRC, supposed
to set badbit, and then if the badbit flag is set in the exception
state, they are supposed to discard the caught exception and throw one
of their own. The default is just to set badbit and return.

(This isn't how we would design a library these days, but it was
thought important to accommodate old programs that don't know about
exceptions.)

Since the implied result of using a facet not found in a locale is
throwing bad_cast, and the implied result of a thrown exception is
to "call setstate(badbit) (which may throw)", it seems clear what
must be done.

I don't see any need to provide any support for implicit specializations
of locale facets where they are not required.  If we were to support 
ctype<unsigned char>, what about ctype<long long>, or ctype<double>?
Programs that relied any of those wouldn't be even slightly portable.

Nathan Myers
ncm at cantrip dot org


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]