std::tstring

2010-09-24

 

If you work with Windows API or MFC you probably know TCHAR. TCHAR is a macro that evaluates either to char or wchar_t, depending if you compile your project as Unicode or not. To make life easy MFC's CString follows TCHAR, which is nice and fluffy if you use MFC.

If you happen to be like me and think that MFC is evil when used in core (non UI) libraries and rather use standard containers, you have come to the problem of how to handle TCHAR with std::string. The simple trick some people do is assume that TCHAR is always wchar_t and simply always use std::wstring. Too bad, when someone wants to build a non Unicode version of the library.

If you happen to look at the MSDN for a solution, you will see that they advise you to use the preprocessor, like this:

#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif

If you ever wondered why the method GetObject will not link? Well, then you have seen why using the preprocessor is not such a hot idea for this. In the Windows API the function is a preprocessor macro that evaluates to either GetObjectW or GetObjectA depending on the value of _UNICODE. Even if your symbol happen to be nested in a different namespace or class, that does not interest the preprocessor, it will still be modified. The trouble starts when the one include path adds the macro and an other does not.

A more robust solution is to use the fact that std::string and std::wstring are typedefs of the template class std::basic_string. By defining the following:

namespace std
{
    typedef basic_string<TCHAR> tstring;
}

You get a std::tstring that does not clutter other namespaces. In the end it evaluates the the exact same as std::string or std::wstring. As a matter of fact you can do this with all charset dependent classes, such as streams. Here my tstring.h header:

#include <tchar.h>
#include <string>
#include <fstream>
#include <sstream>

namespace std
{
    typedef basic_string<TCHAR>         tstring;

    typedef basic_ostream<TCHAR>        tostream;
    typedef basic_istream<TCHAR>        tistream;
    typedef basic_iostream<TCHAR>       tiostream;

    typedef basic_ifstream<TCHAR>       tifstream;
    typedef basic_ofstream<TCHAR>       tofstream;
    typedef basic_fstream<TCHAR>        tfstream;

    typedef basic_stringstream<TCHAR>   tstringstream;
}