Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Wide Streams

A wide stream is a stream class that handles wide characters. All the examples so far (except for the last traits example in Chapter 3) have used narrow streams that hold instances of char. Since stream operations are essentially the same no matter the underlying character type, they are encapsulated generically as templates. So all input streams, for example, are connected to the basic_istream class template:

template<class charT, class traits = char_traits<charT> >
class basic_istream {...};
 

In fact, all input stream types are specializations of this template, according to the following type definitions:

typedef basic_istream<char> istream;
typedef basic_istream<wchar_t> wistream;
typedef basic_ifstream<char> ifstream;
typedef basic_ifstream<wchar_t> wifstream;
typedef basic_istringstream<char> istringstream;
typedef basic_istringstream<wchar_t> wistringstream;
 

All other stream types are defined in similar fashion.

In a perfect world, this is all you d need to create streams of different character types. But things aren t that simple. The reason is that the character-processing functions provided for char and wchar_t don t have the same names. To compare two narrow strings, for example, you use the strcmp( ) function. For wide characters, that function is named wcscmp( ). (Remember these originated in C, which does not have function overloading, hence unique names are required.) For this reason, a generic stream can t just call strcmp( ) in response to a comparison operator. There needs to be a way for the correct low-level functions to be called automatically.

The solution is to factor out the differences into a new abstraction. The operations you can perform on characters have been abstracted into the char_traits template, which has predefined specializations for char and wchar_t, as we discussed at the end of the previous chapter. To compare two strings, then, basic_string just calls traits::compare( ) (remember that traits is the second template parameter), which in turn calls either strcmp( ) or wcscmp( ), depending on which specialization is being used (transparent to basic_string).

You only need to be concerned about char_traits if you access the low-level character processing functions; most of the time you don t care. Consider, however, making your inserters and extractors more robust by defining them as templates, just in case someone wants to use them on a wide stream.

To illustrate, recall again the Date class inserter from the beginning of this chapter. We originally declared it as:

ostream& operator<<(ostream&, const Date&);
 

This accommodates only narrow streams. To make it generic, we simply make it a template based on basic_ostream:

template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const Date& d) {
charT fillc = os.fill(os.widen('0'));
charT dash = os.widen('-');
os << setw(2) << d.month << dash
<< setw(2) << d.day << dash
<< setw(4) << d.year;
os.fill(fillc);
return os;
}
 

Notice that we also have to replace char with the template parameter charT in the declaration of fillc, since it could be either char or wchar_t, depending on the template instantiation being used.

Since you don t know when you re writing the template which type of stream you have, you need a way to automatically convert character literals to the correct size for the stream. This is the job of the widen( ) member function. The expression widen('-'), for example, converts its argument to L - (the literal syntax equivalent to the conversion wchar_t( - )) if the stream is a wide stream and leaves it alone otherwise. There is also a narrow( ) function that converts to a char if needed.

We can use widen( ) to write a generic version of the nl manipulator we presented earlier in the chapter.

template<class charT, class traits>
basic_ostream<charT,traits>&
nl(basic_ostream<charT,traits>& os) {
return os << charT(os.widen('\n'));
}
 
Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire