Home | Libraries | People | FAQ | More |
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.
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 SP6) | 1200 |
Microsoft embedded Visual C++ 4.0 | 1200-1202 (cross compilers) |
using
-declarationsChaining 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 }
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; }
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.
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.
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 }
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" };
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 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 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
is not built-inThe 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.
const X *
does not
workTrying 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.
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.
Revised 04 December, 2006
Copyright © 2001-2002 Jens Maurer
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)