Apache C++ Standard Library User's Guide

## 41.2 Defining Traits and Facets for User-Defined Types

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 `char`s. The `ctype` facet provides character classification and manipulation routines, including the method for converting the new type to and from simple `char`s.

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 `char`s to the user-defined character type, and the narrow function provides conversions from the user-defined type to simple `char`s.

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;

    };