<para>The solution is surprisingly easy. The original answer was
posted on Usenet, and a revised version appears in Herb Sutter's
book <emphasis>Exceptional C++</emphasis> and on his website as <linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://www.gotw.ca/gotw/029.htm">GotW 29</link>.
</para>
<para>See? Told you it was easy!</para>
<para>
<emphasis>Added June 2000:</emphasis> The May 2000 issue of C++
Report contains a fascinating <linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://lafstern.org/matt/col2_new.pdf"> article</link> by
Matt Austern (yes, <emphasis>the</emphasis> Matt Austern) on why
case-insensitive comparisons are not as easy as they seem, and
why creating a class is the <emphasis>wrong</emphasis> way to go
about it in production code. (The GotW answer mentions one of
the principle difficulties; his article mentions more.)
</para>
<para>Basically, this is "easy" only if you ignore some things,
things which may be too important to your program to ignore. (I chose
to ignore them when originally writing this entry, and am surprised
that nobody ever called me on it...) The GotW question and answer
remain useful instructional tools, however.
</para>
<para><emphasis>Added September 2000:</emphasis> James Kanze provided a link to a
Technical Report discussing case handling</link>, which provides some
very good information.
</para>
</section>
<sectionxml:id="strings.string.character_types"xreflabel="Arbitrary Characters"><info><title>Arbitrary Character Types</title></info>
<para>
</para>
<para>The <code>std::basic_string</code> is tantalizingly general, in that
it is parameterized on the type of the characters which it holds.
In theory, you could whip up a Unicode character class and instantiate
<code>std::basic_string<my_unicode_char></code>, or assuming
that integers are wider than characters on your platform, maybe just
declare variables of type <code>std::basic_string<int></code>.
</para>
<para>That's the theory. Remember however that basic_string has additional
type parameters, which take default arguments based on the character
type (called <code>CharT</code> here):
</para>
<programlisting>
template <typename CharT,
typename Traits = char_traits<CharT>,
typename Alloc = allocator<CharT>>
class basic_string { .... };</programlisting>
<para>Now, <code>allocator<CharT></code> will probably Do The Right
Thing by default, unless you need to implement your own allocator
for your characters.
</para>
<para>But <code>char_traits</code> takes more work. The char_traits
template is <emphasis>declared</emphasis> but not <emphasis>defined</emphasis>.
That means there is only
</para>
<programlisting>
template <typename CharT>
struct char_traits
{
static void foo (type1 x, type2 y);
...
};</programlisting>
<para>and functions such as char_traits<CharT>::foo() are not
actually defined anywhere for the general case. The C++ standard
permits this, because writing such a definition to fit all possible
CharT's cannot be done.
</para>
<para>The C++ standard also requires that char_traits be specialized for
instantiations of <code>char</code> and <code>wchar_t</code>, and it
is these template specializations that permit entities like
<code>basic_string<char,char_traits<char>></code> to work.
</para>
<para>If you want to use character types other than char and wchar_t,
such as <code>unsigned char</code> and <code>int</code>, you will
need suitable specializations for them. For a time, in earlier
versions of GCC, there was a mostly-correct implementation that
let programmers be lazy but it broke under many situations, so it
was removed. GCC 3.4 introduced a new implementation that mostly
works and can be specialized even for <code>int</code> and other
built-in types.
</para>
<para>If you want to use your own special character class, then you have
<linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00163.html">a lot
of work to do</link>, especially if you with to use i18n features
(facets require traits information but don't have a traits argument).
</para>
<para>Another example of how to specialize char_traits was given <linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00260.html">on the
mailing list</link> and at a later date was put into the file <code>
include/ext/pod_char_traits.h</code>. We agree
that the way it's used with basic_string (scroll down to main())
doesn't look nice, but that's because <linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00236.html">the
nice-looking first attempt</link> turned out to <linkxmlns:xlink="http://www.w3.org/1999/xlink"xlink:href="http://gcc.gnu.org/ml/libstdc++/2002-08/msg00242.html">not
be conforming C++</link>, due to the rule that CharT must be a POD.