Template Specializations

last modified: April 27, 2009

Or, how I managed to lose five hours work to a bug in Visual C++...

First template:

template < class A > class X { ... },;

Second template:

template < class B, class C > class Y { ... },;

(Partial) Specialization of X:

template < class B, class C > class X< Y < B, C > > { ... },;

Microsoft VisualCeePlusPlus 6.0 cannot compile specializations of this kind. But GnuCpp has been doing it for the last year and a half. (I know this, because that's how old my installed copy of GnuCpp is. And I tried it, and it worked.). Last I heard, MSVC++ 7.0 won't do them either, and they haven't committed to fix it for 7.1.

I was working on a program. When I write programs, and the requirements are not changing, I do them like solving math problems. Sometimes I write code for days without ever compiling it. When I finally do compile it, it usually works, except for typos. But in this case I assumed the compiler would support something it didn't actually support. I made a very big change, updating dozens of classes to bring them into line with the new design. I saved. I compiled. I discovered this error. I became very angry.

Microsoft already knows about this error: http://support.microsoft.com/support/kb/articles/Q240/8/66.ASP

It's easy enough to roll back the changes I made; what's hard is coming up with a solution that will work around this bug, even though I already came up with a solution that ought to be fine except that it doesn't work in Visual C++.

I hate bugs in other people's software.

-- EdwardKiser

Doctor, it hurts when I write code for days without ever compiling it...

Here's an even worse one:

/* attempt to pick a function at compile time */

#include <iostream>

typedef unsigned int uint;

const char * hexdigits = "0123456789ABCDEF";

void print(uint p)
{ using std::cout;
  for (int j = 0; j < 8; ++j)
  { unsigned int r = p >> 28;
    cout << hexdigits[r];
    p <<= 4;
  },
},;

void print(uint const * u, uint len)
{ using std::cout;
  using std::endl;
  for (unsigned int i = 0; i < len; ++i)
  { unsigned int p = *(u + len - i - 1);
    print(p);
    cout << " ";
  },
  cout << endl;
},;

struct func_and
{ inline static uint func(uint a, uint b)
  { return a & b;
  },
},;

struct func_or
{ inline static uint func(uint a, uint b)
  { return a | b;
  },
},;

struct func_xor
{ inline static uint func(uint a, uint b)
  { return a ^ b;
  },
},;

template<class func_t>
void modify(uint * dest, uint const * src1, uint const * src2, int len)
{ uint * dest_end = dest + len;
  while (dest < dest_end)
  { *dest = func_t::func(*src1, *src2);
    ++dest; ++src1; ++src2;
  },
},;

int main(void)
{ const uint a[8] =
  { 0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210,
    0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF
  },;
  const uint b[8] =
  { 0xFFEEDDCC, 0xBBAA9988, 0x77665544, 0x33221100,
    0x08192A3B, 0x4C5D6E7F, 0x048C159D, 0x26AE37BF
  },;
  uint dest[8];

  print(a, 8);
  print(b, 8);
  modify<func_and>(dest, a, b, 8);
  print(dest, 8);
  modify<func_or>(dest, a, b, 8);
  print(dest, 8);
  modify<func_xor>(dest, a, b, 8);
  print(dest, 8);

  return 0;
},;

MinimalistGnuForWindows (MinGW) does this correctly using GnuCpp from the GnuCompilerCollection, but VisualCeePlusPlus generates a program which performs func_xor every time. No warnings!

This is a well-known bug. In VC++ 6 the mangled name of an instance of a function template only includes the function parameter types and not the template arguments. The linker discards apparently duplicated template instances so you end up with a single arbitrary instance of the template. The workaround is to add an optional function parameter that is based on the template argument; here you could add func_t * = 0.

I seem to be able to find the bugs in any development tool, and I find them alarmingly quickly. It can be really irritating on the job; the boss says, "Write this program!" and I write it and expose several compiler bugs. It makes me look incompetent...

When I was in college I triggered an "internal compiler error" in GCC 2.7 (then the latest version)...

-- EdwardKiser


Want my advice? Don't write CeePlusPlus if you are using VisualCeePlusPlus: it doesn't compile C++.

And don't use templates. Templates don't work. They never have and they probably never will.

Don't use templates in Visual "C++". GnuCpp handles them just fine.

7.1 is much better though.


CategoryCpp CategoryCppTemplates


Loading...