Template Specializations

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
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
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,
  1. x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF
};
const uint b[8] =
{ 0xFFEEDDCC, 0xBBAA9988, 0x77665544, 0x33221100,
  1. x08192A3B, 0x4C5D6E7F, 0x048C159D, 0x26AE37BF
};
uint dest[8];
print(a, 8);
print(b, 8);
modify(dest, a, b, 8);
print(dest, 8);
modify(dest, a, b, 8);
print(dest, 8);
modify(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