| Home | Libraries | People | FAQ | More

# Portability Hints: Microsoft Visual C++ 6.0 SP4

Similar to the portability hints for Borland C++, this page provides hints on some language features of the Microsoft Visual C++ version 6.0 service pack 4 compiler. A list of acknowledged deficiencies can be found at the Microsoft support site.

Each entry in the following list describes a particular issue, complete with sample source code to demonstrate the effect. Most sample code herein has been verified to compile with gcc 2.95.2 and Comeau C++ 4.2.44.

## Preprocessor symbol

The preprocessor symbol `_MSC_VER` is defined for all Microsoft C++ compilers. Its value is the internal version number of the compiler interpreted as a decimal number. Since a few other compilers also define this symbol, boost provides the symbol `BOOST_MSVC`, which is defined in boost/config.hpp to the value of _MSC_VER if and only if the compiler is really Microsoft Visual C++. The following table lists some known values.

Compiler | `BOOST_MSVC` value
--- | ---
Microsoft Visual C++ 6.0 (up to SP4) | 1200

## Core Language

### [chained using] Chaining `using`-declarations

Chaining `using`-declarations does not work.

    void f();

    namespace N {
      using ::f;
    }

    void g()
    {
      using N::f;  // C2873: 'f': the symbol cannot be used in a using-declaration
    }

### [explicit-instantiation] Explicit function template instantiation

Trying to explicitly instantiate a function template leads to the wrong function being called silently.

    #include <stdio.h>

    template<class T>
    void f()
    {
      printf("%d\n", sizeof(T));
    }

    int main()
    {
      f<double>();      // output: "1"
      f<char>();        // output: "1"
      return 0;
    }

### [for-scoping] Scopes of definitions in for-loops

The scope of variable definitions in `for` loops should be local to the loop's body, but it is instead local to the enclosing block.

    int main()
    {
      for(int i = 0; i < 5; ++i)
       ;
      for(int i = 0; i < 5; ++i)  // C2374: 'i': Redefinition; multiple initialization
       ;
      return 0;
    }

Workaround: Enclose the offending `for` loops in another pair of curly braces.

Another possible workaround (brought to my attention by Vesa Karvonen) is this:

    #ifndef for
    #define for if (0) {} else for
    #endif

Note that platform-specific inline functions in included headers might depend on the old-style `for` scoping.

### [inclass-member-init] In-class member initialization

In-class member initialization, required to implement a Standard-conforming `std::numeric_limits` template, does not work.

    struct A
    {
      static const int i = 5;      // "invalid syntax for pure virtual method"
    };

Workaround: Either use an enum (which has incorrect type, but can be used in compile-time constant expressions), or define the value out-of-line (which allows for the correct type, but prohibits using the constant in compile-time constant expressions). See Coding Guidelines for Integral Constant Expressions for guidelines how to define member constants portably in boost libraries.

### [koenig-lookup] Argument-dependent lookup

Argument-dependent lookup, also called Koenig lookup, works for overloaded operators, but not for ordinary functions. No additional namespaces induced from the argument types seem to be considered.

    namespace N {
      struct A {};
      void f(A);
    }

    void g()
    {
      N::A a;
      f(a);     // 'f': undeclared identifier
    }

### [template-friend] Templates as friends

A Template cannot be declared a friend of a class.

    template<class T>
    struct A {};

    struct B
    {
      template<class T>
      friend struct A;     // "syntax error"
    };

### [member-template-outofline] Out-of-line definitions of member templates

Defining member templates outside their enclosing class does not work.

    template<class T>
    struct A
    {
      template<class U>
      void f();
    };

    template<class T>
    template<class U>   // "syntax error"
    void A<T>::f()      // "T: undeclared identifier"
    {
    }

Workaround: Define member templates in-line within their enclosing class.

### [partial-spec] Partial specialization

Partial specialization of class templates does not work.

    template<class T>
    struct A {};

    template<class T>
    struct B {};

    template<class T>
    struct A<B<T> > {};  // template class was already defined as a non-template

Workaround: In some situations where interface does not matter, class member templates can simulate partial specialization.

### [template-value] Dependent template value parameters

Template value parameters whose type depends on a previous template parameter provoke an internal compiler error if the correct syntax (with "typename") is used.

    template<class T, typename T::result_type> // C1001: INTERNAL COMPILER ERROR: msc1.cpp, line 1794
    struct B {};
     // (omit "typename" and it compiles)

Workaround: Leave off the "typename" keyword. That makes the program non-conforming, though.

### [wchar_t] `wchar_t` is not built-in

The type `wchar_t` is not a built-in type.

    wchar_t x;  // "missing storage class or type identifier"

Workaround: When using Microsoft Visual C++, the header boost/config.hpp includes `<cstddef>`, which defines `wchar_t` as a typedef for `unsigned short`. Note that this means that the compiler does not regard `wchar_t` and `unsigned short` as distinct types, as is required by the standard, and so ambiguities may emanate when overloading on `wchar_t`. The macro `BOOST_NO_INTRINSIC_WCHAR_T` is defined in this situation.

### [delete-const-pointer] Deleting `const X *` does not work

Trying to delete a pointer to a cv-qualified type gives an error:

    void f()
    {
      const int *p = new int(5);
      delete p;        // C2664: cannot convert from "const int *" to "void *"
    }

Workaround: Define the function

    inline void operator delete(const void *p) throw()
    { operator delete(const_cast<void*>(p)); }

and similar functions for the other cv-qualifier combinations, for operator delete[], and for the `std::nothrow` variants.

## Standard Library

### [clib-namespace] C library names in global namespace instead of std

Library names from the <c...> headers are in the global namespace instead of namespace std.

Workaround: The header boost/config.hpp will define BOOST_NO_STDC_NAMESPACE. It can be used as follows:

    # ifdef BOOST_NO_STDC_NAMESPACE
        namespace std { using ::abs; using ::fabs; }
    # endif

Because std::size_t and std::ptrdiff_t are so commonly used, the workaround for these is already provided in boost/config.hpp.

2001-05-04 Jens Maurer