Re: Allowing duplicate template specialisations
On Mon, 17 Jan 2011 13:56:20 CST, Martin B. wrote:
On 17.01.2011 12:50, Alexander Lamaison wrote:
On Thu, 13 Jan 2011 20:07:20 CST, Martin B. wrote:
On 13.01.2011 10:27, Alexander Lamaison wrote:
Is there a way to allow multiple definitions of the same template
specialisation?
Sorry. I misread your OP. It wasn't immediately clear to me that you
have multiple definitions in the same translation unit.
What I do not understand is how -- given that each header will include a
header guard -- it is possible to have multiple definitions of the same
thing in the same compilation unit: It's only possible if the same thing
is actually defined twice in different locations, and while this may not
necessarily be an "error" as such, it certainly feels very weird -- a
specialization is *not* a declaration and as such I would certainly
expect it to be defined only once.
Yes, the specialisations are defined twice in different locations (so
hearder guards won't help) and, yes, this is a bit wierd.
If the specializations are auto-generated by a code generator it may be
a usable workaround to generate #define/ifdef macros alongside to
prevent multiple definitions of the same IID specializations in the same
translation unit.
Ok, to explain _why_ I need this, I'm going to have to paint the picture
more fully. Please bear with me :P
In Microsoft COM, each interface type is associated with an UUID. For
example, the following code requests a certain type of interface pointer
from an object using the UUID (error checking ommitted):
IFoo* pFoo = NULL;
object->QueryInterface(IID_IFoo, (void**)pFoo);
IID_IFoo is the UUID of IFoo and is generated by MIDL, the code generator
for COM that takes interface definition in IDL and generates C/C++ headers.
So far, so good. Enter generic programming. The hard-coded UUID becomes a
problem. Consider:
template<typename ITF, typename T>
ITF* query_interface(T* object) {
ITF* pOut = NULL;
object->QueryInterface(IID_ITF, (void**)pOut);
return pOut;
}
IFoo* pFoo = query_interface<IFoo>(object);
What is IID_ITF?! Nothing sensible at the moment. MIDL certainly can't
generate template-aware code. So what MS did was introduce a compiler
extension, __uuidof, that renders the correct UUID based on the type of the
interface pointer:
template<typename ITF, typename T>
ITF* query_interface(T* object) {
ITF* pOut = NULL;
object->QueryInterface(__uuidof(pOut), (void**)pOut);
return pOut;
}
This is used throughout ATL and WTL (very popular MS libraries for
programming in COM using templates). Alas, it's also the reason that any
project using ATL/WTL can't be compiled for Windows using GCC (Google
Chrome, for example).
The comtype template and specialisations are a portable solution introduced
by the Comet template library (http://bitbucket.org/sofusmortensen/comet)
and can be used just like __uuidof:
template<typename T> struct comtype {};
template<> struct comtype<IUnknown> {
static const IID& uuid() { return IID_IUnknown; }
}
template<typename T> inline IID& uuidof(Itf*) {
return comtype<T>::uuid();
}
template<typename ITF, typename T>
ITF* query_interface(T* object) {
ITF* pOut = NULL;
object->QueryInterface(uuidof(pOut), (void**)pOut);
return pOut;
}
*Now finally we come my problem*: The one downside is that every interface
type used by generic code in this way must have an associated comtype
specialisation that links it back to a MIDL-generated IID_Blah UUID. This
worked fine for a while; I would define all the necessary specialisations
in every compilation unit.
But this quickly became ridiculous: every .cpp file started with a long
list of specialiations, many of which were shared with other .cpp files.
As the code that needed these specialisations was often in header files, I
moved the specialisations there. This again worked for a while but if I
had two headers that both needed comtype<IShellFolder> (common in my
project) and each header contained the specialisation, they would conflict
if both were included in a single compilation unit.
One solution would be to include comtype specialisations common to two
headers, from a third header procted by the usual include guards. However,
this also doesn't scale. If a third-party library also uses comet and
defines such specialisations they will, again, conflict. Not to mention
that my own code is now split into independently-developed, self-contained
libraries that must each define the specialisations.
Some magic global header in the sky that contains comtypes for every
possible interface just isn't realistic. And so I am stuck. I would like
to be able to define comtype specialisations anywhere in a decentralised
manner and have the compiler pick one. They should all be identical.
Any ideas?
Many thanks for getting this far!
Alex
--
Easy SFTP for Windows Explorer (http://www.swish-sftp.org)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]