template class traits = char_traits class allocator = allocator class basic_string; The template parameter charT represents the underlying character type, which is usually either char or wchar_t. The primary char_traits template is typically empty, and specializations for char and wchar_t are provided by the standard library. Here is the specification of the specialization char_traits template<> struct char_traits typedef char char_type; typedef int int_type; typedef streamoff off_type; typedef streampos pos_type; typedef mbstate_t state_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, size_t n); static size_t length(const char_type* s); static const char_type* find(const char_type* s, size_t n, const char_type& a); static char_type* move(char_type* s1, const char_type* s2, size_t n); static char_type* copy(char_type* s1, const char_type* s2, size_t n); static char_type* assign(char_type* s, size_t n, 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 int_type eof(); }; These functions are used by the basic_string class template for character-based operations common to string processing. When you declare a string variable, such as:. std::string s; you are actually declaring s as follows (because of the default template arguments in the specification of basic_string): std::basic_string std::allocator Because the character traits have been separated from the basic_string class template, you can supply a custom traits class to replace std::char_traits. The following example illustrates this flexibility. //: C05:PoohCorner.cpp // Illustrates traits classes #include using namespace std; // Item classes (traits of guests): class Water { public: friend ostream& operator<<(ostream& os, const Water&) { return os << "Water"; } }; class Milk { public: friend ostream& operator<<(ostream& os, const Milk&) { return os << "Milk"; } }; class Honey { public: friend ostream& operator<<(ostream& os, const Honey&) { return os << "Honey"; } }; class Cookies { public: friend ostream& operator<<(ostream& os, const Cookies&) { return os << "Cookies"; } }; // Guest classes: class Bear { public: friend ostream& operator<<(ostream& os, const Bear&) { return os << "Pooh"; } }; class Boy { public: friend ostream& operator<<(ostream& os, const Boy&) { return os << "Christopher Robin"; } }; // Primary traits template (empty—could hold common types) template class GuestTraits; // Traits specializations for Guest types template<> class GuestTraits public: typedef Water beverage_type; typedef Honey snack_type; }; template<> class GuestTraits public: typedef Milk beverage_type; typedef Cookies snack_type; }; // A custom traits class class MixedUpTraits { public: typedef Milk beverage_type; typedef Honey snack_type; }; // The Guest template (uses a traits class) template< class Guest, class traits = GuestTraits class PoohCorner { Guest theGuest; typedef typename traits::beverage_type beverage_type; typedef typename traits::snack_type snack_type; beverage_type bev; snack_type snack; public: PoohCorner(const Guest& g) : theGuest(g), bev(beverage_type()), snack(snack_type()) {} void entertain() { cout << "Entertaining " << theGuest << " serving " << bev << " and " << snack << endl; } }; int main() { Boy cr; PoohCorner pc1.entertain(); Bear pb; PoohCorner pc2.entertain(); PoohCorner pc3.entertain(); } ///:~. In this program, instances of the guest classes Boy and Bear are served items appropriate to their tastes. Boys like milk and cookies and Bears like water and honey. This association of guests to items is done via specializations of a primary (empty) traits class template. The default arguments to PoohCorner ensure that guests get their proper items, but you can override this by simply providing a class that meets the requirements of the traits class, as we do with the MixedUpTraits class above. The output of this program is:. Entertaining Christopher Robin serving Milk and Cookies Entertaining Pooh serving Water and Honey Entertaining Pooh serving Milk and Honey Using traits provides two key advantages: (1) it allows flexibility in pairing objects with associated attributes or functionality, and (2) it keeps template parameter lists small and readable. If 30 types were associated with a guest, it would be inconvenient to have to specify all 30 arguments directly in each PoohCorner declaration. Factoring the types into a separate traits class simplifies things considerably. The traits technique is also used in implementing streams and locales, as we showed in Chapter 4.