# Known problems with the Microsoft Visual C++ compiler, version 6.0:

The Microsoft Visual C++ compiler, version 6.0 (which we shall call VC++ 6.0) fails to match the C++ standard in several ways that prevent some of the code in Accelerated C++ from compiling properly. This page describes the problems and shows how to change the code to avoid the problems.

Some of these problems recur throughout the text. For example, any problem that affects the student grading program will occur in Chapters 4, 6, 9, and 13, because that program occurs in all those chapters. We describe these pervasive problems first, followed by a list of problems specific to each chapter.

We have reported these bugs to the Microsoft folks and they are working on fixes. For example, in the first section below, which described persvasive problems, problem #2 has been fixed in Service Pack 4.

In each case we offer a suggested workaround. These workarounds generally use the `#ifdef` preprocessor directive. That directive works similarly to the `#ifndef` directive that we described in §4.3/67. The `#ifdef` directive asks the preprocessor to process text up to the corresponding `#endif` if the preprocessor symbol following `#ifdef` is defined. The Microsoft compiler defines the symbol `_MSC_VER`, which we test to conditionally include code special to the Microsoft compiler.

# Pervasive bugs:

1. When you write a `using` declaration for a container type, such as `vector`:
   `
   using std::vector;`
   you should then be able to use members of that container type, particularly type members, without further ado. For example:
   `
   vector<double>::size_type n = 0;`
   Unfortunately, VC++ 6.0 complains with a message that says something like
   `
   vector<double, class std::allocator<double> > : is not a class or namespace name`
   The easiest way to work around this problem is to include `std::` as an explicit qualifier, even though it should not be necessary:
   `
   using std::vector;
   #ifdef _MSC_VER
   std::vector<double>::size_type n = 0;
   #else
   vector<double>::size_type n = 0;
   #endif`
2. VC++ 6.0 prior to Service Pack 4 does not properly handle function arguments passed to template functions. This bug affects the student grading program that appears in a number of places in Accelerated C++. The problem occurs when using `compare` as an argument to the standard-library `sort` function:
   `
   sort(vs.begin(), vs.end(), compare);`

   One workaround is to define the `<` operator for `Student_info`, which `sort` can use automatically. First define the appropriate function:

   `
   #ifdef _MSC_VER
   bool operator<(const Student_info& x, const Student_info& y)
   {
   return x.name() < y.name();
   }
   #endif`
   Then replace the relevant calls as follows:
   `
   #ifdef _MSC_VER
   sort(vs.begin(), vs.end());
   #else
   sort(vs.begin(), vs.end(), compare);
   #endif`
   A simpler workaround, but one that uses language features that do not appear until Chapter 10, is to place an explicit `&` operator before `compare`:
   `
   #ifdef _MSC_VER
   sort(vs.begin(), vs.end(), &compare);
   #else
   sort(vs.begin(), vs.end(), compare);
   #endif`
   We believe that this bug was fixed in Service Pack 4.
3. The MS library fails to properly pad `string` output. Thus calls, such as
   `
   cout << setw(maxlen+1) << students[i].name;`
   should pad the output so that whatever value is in `students[i].name` is padded out to use at least `maxlen+1` characters. Instead, the library provides no padding and so the names run into the next output.

   When we wrote the book, we assumed that fixing this problem would make our programs correct. Unfortunately, because of our inability to test the code, we failed to realize that `setw` would pad on the left rather than on the right, which is not the behavior we wanted.

   The easiest way to work around both of these problems is to write the required padding explicitly. For example:

   `
   #ifdef _MSC_VER
   cout << students[i].name;
   cout << string(maxlen - students[i].name.size() + 1, ' ');
   #else
   cout << setw(maxlen+1) << students[i].name;
   #endif`

   We have adopted this approach in the second and subsequent printings of Accelerated C++.

4. The MS library does not define the `min` and `max` algorithms, which should be found in `<algorithm>` The workaround we use is to define a new header file, say `minmax.h`, which we include in any file that uses these functions:
   `
   #ifndef GUARD_minmax_H
   #define GUARD_minmax_H
   #ifdef _MSC_VER
   // needed to cope with bug in MS library:
   // it fails to define min/max
   template <class T> inline T max(const T& a, const T& b)
   {
   return (a > b) ? a : b;
   }
   template <class T> inline T min(const T& a, const T& b)
   {
   return (a < b) ? a : b;
   }
   #endif
   #endif`

# Notes about specific chapters (including localized bugs):

## Chapters 0-2

The code in these chapters should compile without complaint.

## Chapter 3

Programs in this chapter will require workarounds for the pervasive bugs described above. In particular, the definition of `vec_sz` near the top of page 47 needs to be changed from

`typedef vector<double>::size_type vec_sz;`

to

`typedef std::vector<double>::size_type vec_sz;`

## Chapters 4-5

Programs in these chapters will require workarounds for the pervasive bugs described above.

## Chapter 6

Programs in this chapter will require workarounds for the pervasive bugs described above.

In additon, although the program to find URLs should have `using` declarations for the character classification functions, `isalpha` and `isalnum`, VC++ 6.0 mistakenly says that these functions are not part of the `std` namespace. You can work around this bug by omitting the `using` declarations:

`#ifndef _MSC_VER
using std::isalpha;
using std::isalnum;
#endif`

## Chapter 7

Programs in this chapter will have to work around the first pervasive bug described above.

## Chapter 8

1. Problem #1 from above applies also to generic uses of containers and requires a similar workaround. For example, in the generic median program, it should be legal to write:
   `
   using std::vector;
   typedef typename vector<T>::size_type vec_sz;`
   But for VC++ 6.0, we must instead write:
   `
   typedef typename std::vector<T>::size_type vec_sz;`
2. In the `split` function, it is correct to include a `using` declaration for the `std::isspace` function, but as in Chapter 6 and the `isalpha` and `isalnum` functions, VC++ 6.0 incorrectly says that `isspace` is not in namespace `std`. Use the same workaround--do not include a `using` declaration for `isspace`.

## Chapter 9

Programs in this chapter will require workarounds for the pervasive bugs described above.

## Chapter 10

The code in this chapters should compile without complaint.

## Chapter 11

The `allocate` member of class `std::allocator` is defined to take a single argument of type `size_t`. VC++ 6.0 incorrectly requires a second argument, which it uses as a hint to optimize the performance of `allocate`. A null pointer can be passed as the second argument, which has the effect of not offering a hint. To work around the problem, rewrite each of the calls to `allocate` to pass this extra, non-standard argument.

For example, we can rewrite the call to `allocate` in `Vec::create` as follows:

`#ifdef _MSC_VER

data = alloc.allocate(n, 0);

#else

data = alloc.allocate(n);

#endif`

## Chapter 12

Similar to the problems in Chapters 6 and 8, where VC++ 6.0 fails to include the character classification functions (`isalpha`, `isalnum`, `isspace` etc.) as part of the `std` namespace, it also fails to include the `strlen` function in `std`. The workaround is analogous: Omit the qualification of `std::strlen`.

For example, in the `Str` constructor that takes a `const char*`:

`#ifdef _MSC_VER

std::copy(cp, cp + strlen(cp), std::back_inserter(data));

#else

std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));

#endif`

## Chapter 13

Programs in this chapter will require workarounds for the pervasive bugs described above.

In addition, the return type for the `clone` function in class `Grad` must be changed to be a `Core*` rather than a `Grad*` as written in the book:

`
#ifdef _MSC_VER

Core* clone() const { return new Grad(*this); }

#else

Grad* clone() const { return new Grad(*this); }

#endif`

because VC++ 6.0 does not yet allow a virtual function returning a pointer (or reference) to a base class to be defined in a derived class to return a pointer (or reference) to the derived type.

## Chapter 14

The programs that reimplement earlier programs using `Handle` or `Ptr` will have to be fixed as described in the related chapter. For example, the student grading solution that uses a `vector< Handle<Core> >` will have to be corrected for the pervasive problems described above. Similarly, the `Str` class that is reimplemented using a `Ptr` will need to be adjusted to account for the MS bug related to `strlen` described in Chapter 12.

## Chapter 15

Various functions use the `max` algorithm from the library and so, as described above, the calls to `max` will have to be replaced by corresponding calls to your own version.

For example, in `VCat_Pic`: ``

class VCat_Pic: public Pic_base
{

//...

wd_sz width() const {

return std::max(top->width(), bottom->width());

}

could be rewritten as: `

class VCat_Pic: public Pic_base
{

//...

wd_sz width() const {

#ifndef _MSC_VER

return std::max(top->width(), bottom->width());

#else

return max(top->width(), bottom->width());

}

`
Of course, a declaration for your version of `max` would also have to be included in the file in which this code resides.

## Chapter 16

Programs in this chapter will require workarounds for the pervasive bugs described above.