[Insight-developers] Coding style, MSVC INTERNAL COMPILER ERRORs, and enums

Brad King brad.king@kitware.com
Tue, 13 Mar 2001 15:30:10 -0500 (EST)


Hello, all:

I just tracked down another ICE by MSVC related to the bug in it that I
previously reported to the list.  The fix has been checked in, but we can
avoid the issue altogether with a little care in the style of our code.
Here is a typical example that causes the problem:

template <class TInputImage>
class MyClass
{
  void MyMethod(typename TInputImage::PixelType pixel);
};

//...and through some chain of includes when MyClass is used...
template <
  unsigned int VDimension
  > // MSVC fails here with an ICE
class SomeOtherClass { /*...*/ };

The only explanation for this problem is a bug in MSVC's compiler.  The
solution is simple, and should be used anyway just for readability.  Any
type that is qualified inside another type, namespace, or is a typename
type should not be directly used as a method argument.  Instead, typedef
the type and use the new name as the argument.  Here is the example above
with this change:

template <class TInputImage>
class MyClass
{
  typedef typename TInputImage::PixelType InputPixelType;
  void MyMethod(InputPixelType pixel);
};

// MSVC will no longer ICE on a "template <unsigned int>" block.

It would be good if everyone could use this style, both for the ICE
problem, and for readability.  The same thing should be done with enum
values as well (like ImageDimension).  In fact, it is necessary to do this
with enums since the compiler does not get the "typename" hint for an
enum value.

Earlier today I spent an hour tracking down such an enum problem in
itk::DanielssonDistanceMapImageFilter.  Here is a simplified example of
the problem:

template <unsigned int> struct X {};
template <typename T> struct A
{
  void Method(X<T::EnumValue>);
};
template <typename T>
void A<T>::Method(X<T::EnumValue>) {}

GCC gives the following errors while parsing this code:

prototype for `void A<T>::Method(X<T::EnumValue>)' does not match any in
class `A<T>'
candidate is: void A<T>::Method(X<T::EnumValue>)
In method `void A<T>::Method(X<T::EnumValue>)':
template definition of non-template `void A<T>::Method(X<T::EnumValue>)'

Note that the candidate it gives consists of the EXACT SAME text as the
prototype that the candidate does not match!  The solution to this problem
is to make sure the compiler knows that the value is an enum.

template <unsigned int> struct X {};
template <typename T> struct A
{
  enum { EnumValue = T::EnumValue };
  void Method(X<EnumValue>);
};
template <typename T>
void A<T>::Method(X<EnumValue>) {}

This is actually a C++ issue not related to GCC or any other compiler (I
don't have a quote from the C++ standard this time, though).  Again, it
can be fixed with good style in our code.

-Brad