c++boost.gif (8819 bytes) 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