Policies
If you inspect the char_traits specialization for wchar_t, you’ll see that it is practically identical to its char counterpart:
template<>
struct char_traits
typedef wchar_t char_type;
typedef wint_t int_type;
typedef streamoff off_type;
typedef wstreampos 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();
};
The only real difference between the two versions is the set of types involved (char and int vs. wchar_t and wint_t). The functionality provided is the same.[63] This highlights the fact that traits classes are indeed for
It is also useful to be able to associate
//: C05:PoohCorner2.cpp
// Illustrates policy classes
#include
using namespace std;
// Item classes:
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";
}
};
// Traits template
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;
};
// Policy classes (require a static doAction() function)
class Feed {
public:
static const char* doAction() {
return "Feeding";
}
};
class Stuff {
public:
static const char* doAction() {
return "Stuffing";
}
};
// The Guest template (uses a policy and a traits class)
template< class Guest, class Action, 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 << Action::doAction() << " " << theGuest
<< " with " << bev
<< " and " << snack << endl;
}
};
int main() {
Boy cr;
PoohCorner
pc1.entertain();
Bear pb;
PoohCorner
pc2.entertain();
} ///:~.
The Action template parameter in the PoohCorner class expects to have a static member function named doAction( ), which is used in PoohCorner<>::entertain( ). Users can choose Feed or Stuff at will, both of which provide the required function. Classes that encapsulate functionality in this way are referred to as
The curiously recurring template pattern
Any novice C++ programmer can figure out how to modify a class to keep track of the number of objects of that class that currently exist. All you have to do is to add static members, and modify constructor and destructor logic, as follows:.
//: C05:CountedClass.cpp
// Object counting via static members
#include
using namespace std;