4

I'm having a problem getting a program to read from a file based on a template, for example:

bool parse(basic_ifstream<T> &file)
{
    T ch;
    locale loc = file.getloc();
    basic_string<T> buf;
    file.unsetf(ios_base::skipws);
    if (file.is_open())
    {
        while (file >> ch)
        {
            if(isalnum(ch, loc))
            {
                buf += ch;
            }
            else if(!buf.empty())
            {
                addWord(buf);
                buf.clear();
            }
        }
        if(!buf.empty())
        {
            addWord(buf);
        }
        return true;
    }
    return false;
}

This will work when I instantiate this class with <char>, but has problems when I use <wchar_t> (clearly).

Outside of the class, I'm using:

for (iter = mp.begin(); iter != mp.end(); ++iter )
{
    cout << iter->first << setw(textwidth - iter->first.length() + 1);
    cout << " " << iter->second << endl;
}

To write all of the information from this data struct (it's a map<basic_string<T>, int>), and as predicted, cout explodes if iter->first isn't a char array.

I've looked online and the consensus is to use wcout, but unfortunately, since this program requires that the template can be changed at compile time (<char> -> <wchar_t>) I'm not sure how I could get away with simply choosing cout or wcout. That is, unless there way a way to read/write wide characters without changing lots of code.

If this explanation sounds awkwardly complicated, let me know and I'll address it as best I can.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
Mark L.
  • 41
  • 1

2 Answers2

6

Use a traits class. Instead of referencing directly cout in code, you'd reference traits<T>::cout and then specialize traits<char> to std::cout and traits<wchar_t> to wcout.

Updated

template <typename T>
class traits {
public:
    static std::basic_ostream<T>& tout;
};

template<>
std::ostream& traits<char>::tout = std::cout;

template<>
std::wostream& traits<wchar_t>::tout = std::wcout;

int _tmain(int argc, _TCHAR* argv[])
{
    traits<char>::tout<<"Ascii";
    traits<wchar_t>::tout<<L"Unicode";
    return 0;
}
Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
0

Sure, just redefine the templates and use a typedef:

#ifdef USE_UNICODE
typedef wchar_t tchar_t
#else
typedef unsigned char tchar_t
#endif

Then you can use the templates of most standard C++ functions/containers:

typedef std::basic_string<tchar_t> tstring

etc.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552