Here is a test harness for PeterMerel's ExtremeCppForm? (see ExtremeCppFormExample). I've changed his example around some so I'll re-post everything here along with my results:
[came back and threw in a little goodie that's sure to highlight the main problem with this strategy...]
TestInsulated?.cpp:
// Test harness for the Insulated class #include "Insulated.h" #include <iostream> using namespace std; // Will this compile? We want to be able to derive from the insulated class class InsulatedDerivitive? : public Insulated { }; int main() { const char * message = "It worked!"; // Can we change it's state? Insulated insulation_tester(message); // Can we see the new state? if( insulation_tester.Message() == message ) cout << "ok" << endl; else cout << "\"Message\" method failed." << endl; // Did we really allocate enough room? if( sizeof(insulation_tester) >= sizeof(const char*) + sizeof(char[1000]) ) cout << "ok" << endl; else cout << "Instance is not the correct size: " << sizeof(insulation_tester) << endl; return 0; }Insulated.h:
#ifndef INSULATED_H_ #define INSULATED_H_ template< int > class IInsulated { public: IInsulated(const char *Message); const char *Message(); }; typedef IInsulated<0> Insulated; #endifInsulated.cpp:
#include "Insulated.h" #include <iostream> using namespace std; //template<> //class IInsulated<0> // Compiles fine but won't link template class IInsulated<0> // Generates compiler warning { protected: const char *mMessage; char mBigThing[1000]; public: IInsulated<0>(const char *Message):mMessage(Message) { int x; while(x < 1000) { mBigThing[x++] = (char)0xba; if(x >= 1000)break; mBigThing[x++] = (char)0xdb; if(x >= 1000)break; mBigThing[x++] = (char)0xad; } } const char *Message() {return mMessage;} };[I changed the constructor to show that the memory occupied by instances of Insulated are bad, bad, bad. Now neither of the tests will run.] I couldn't get a clean compile, but I did get some very interesting results with the version shown here. VC++ gave me this warning: Insulated.cpp(17) : warning C4660: template-class specialization 'IInsulated<0>' is already instantiated
Insulated.cpp(9) : see declaration of 'IInsulated<0>'When I ran it I got the following results: ok Instance is not the correct size: 1 I dug a little deeper and found that, because of the compilers default alignment, the Insulated object had just enough room to store the pointer so the function appeared to work properly. However, if I initilized mBigThing in the constructor I wrote right into the memory occupied by the 'message' variable in main() after that both the tests failed. -- PhilGoodwin
Hmm. That does sound like a Bad Thing (tm). FWIW I can get rid of the warning in the original by defining an explicit ctor and then doing this in foo.cpp:
#include "foo.h" template<> template struct FooIF<0> { FooIF<0>() : m_bar(0) {} void setBar(int const & i) { m_bar = i; } int const & bar() { return m_bar; } int m_bar; }; // // Okay, now we have to get 'em instantiated explicitly ... // foobar() { Foo foo; foo.bar(); foo.setBar(0); return 0; }I won't have time to try this on Phil's example till this evening. --PM
I hope you guys don't mind me weighing in - I'm more of a Wiki reader than writer. The problem with this idiom is that it violates the One Definition Rule, which says that there can only be a single definition of any given thing across all compilation units.
If a compilation unit only sees the primary template (FooIF) and not its specialization, you'll get a definition of FooIF<0> at first use. That's perhaps not at the typedef, but certainly the first time in client code that you write 'Foo'.
In an nutshell, if you provide a template specialization for something, you must be sure that every piece of client code that might refer to that specialization can actually see it. -- KenShrum?
You're very welcome indeed here Ken. I'd make a case that this doesn't violate the ODR because the header doesn't define the specialized template, only the .cpp file does. Of course we're in the strange, wild, heavily booby-trapped world of LanguageLegalism? ... but here's a link I think backs the contention up: http://www.comnets.rwth-aachen.de/doc/c++std/basic.html#basic.def.odr (point 5).
Thinking more on Phil's version above, though, I think his derived class has to have forced a competing instantiation of the specialized template, and indeed violated ODR. If we do find a safe way to use this idiom, you'll still have to unpack it in order to derive. Bummer. --PeterMerel