A user-defined type requires its own traits class, its own code conversion facet, and its own character classification facet. The traits class defines a conversion state_type and also defines operations such as copying arrays of the type and comparing arrays. The code conversion facet provides conversion to and from simple chars. The ctype facet provides character classification and manipulation routines, including the method for converting the new type to and from simple chars.
The following code shows a traits class declaration for Echar:
struct Etraits { typedef Echar char_type; typedef long int_type; typedef std::streamoff off_type; typedef std::mbstate_t state_type; typedef std::fpos<state_type> pos_type; static void assign (char_type& c1, const char_type& c2); static bool eq(const char_type& c1,const char_type& c2); static bool lt (const char_type& c1, const char_type& c2); static int compare (const char_type* s1, const char_type* s2, std::size_t n); static std::size_t length(const char_type *s); static const char_type* find (const char_type* s, int n, const char_type& a); static char_type* move (char_type* s1, const char_type* s2, std::size_t n); static char_type* copy(char_type *dst,const char_type *src, std::size_t n); static char_type* assign (char_type* s, std::size_t n, const char_type& a); static int_type not_eof(const int_type& c); static char_type to_char_type(const int_type& c); static int_type to_int_type(const char_type& c); static bool eq_int_type(const int_type& c1,const int_type& c2); static state_type get_state(pos_type pos); static int_type eof(); };
See the Apache C++ Standard Library Reference Guide section on char_traits for a complete description of the member functions in a traits class.
To create a new code conversion facet, you must inherit from the std::codecvt template and then override some or all the protected virtual functions. Iostreams calls the protected functions through the public interface defined for std::codecvt. You must also provide a constructor taking a single std::size_t argument, and initialize codecvt with that argument.
A code conversion facet for Echar has a declaration that looks like this:
class Ecodecvt : public std::codecvt<Echar,char,Estate> { public: explicit Ecodecvt (std::size_t refs = 0) : std::codecvt<Echar,char,Estate>(refs) { } protected: virtual result do_out(Estate& state, const Echar* from, const Echar* from_end, const Echar*& from_next, char* to, char* to_limit, char*& to_next) const; virtual result do_in(Estate& state, const char* from, const char* from_end, const char*& from_next, Echar* to, Echar* to_limit, Echar*& to_next) const; virtual result do_unshift(Estate& state, char* to, char* to_limit, char*& to_next) const; virtual int do_encoding() const throw(); virtual bool do_always_noconv() const throw(); virtual int do_length(Estate& state, const char* from, const char* end, size_t maxm) const; virtual int do_max_length() const throw(); };
See Chapter 40 on defining a code conversion facet for more details. Also see the Apache C++ Standard Library Reference Guide section on codecvt for a complete description of member functions.
To create a character classification facet, you must inherit from the std::ctype template and provide implementations for all protected virtual functions. You must also provide a constructor taking a single std::size_t argument, and initialize std::ctype with that argument.
Note that the widen() functions define conversions from simple chars to the user-defined character type, and the narrow function provides conversions from the user-defined type to simple chars.
A character classification facet for Echar has a declaration that looks like this:
class Ectype : public std::ctype<Echar> { public: typedef Echar char_type; explicit Ectype (std::size_t refs = 0) : std::ctype<Echar>(refs) { } // must pass refs onto // the ctype constructor protected: virtual bool do_is(mask m, Echar c) const; virtual const Echar* do_is( const Echar* low, const Echar* high, mask* vec) const; virtual const Echar* do_scan_is( mask m, const Echar* low, const Echar* high) const; virtual const Echar* do_scan_not( mask m, const Echar* low, const Echar* high) const; virtual Echar do_toupper(Echar e) const; virtual const Echar* do_toupper(Echar* low, const Echar* high) const; virtual Echar do_tolower(Echar) const; virtual const Echar* do_tolower(Echar* low, const Echar* high) const; virtual Echar do_widen(char) const; virtual const char* do_widen(const char* lo, const char* hi, Echar* dest) const; virtual char do_narrow(Echar, char dfault) const; virtual const Echar* do_narrow(const Echar* lo, const Echar* hi,char dfault, char* dest) const; };