1/19/2009

01-19-09 - swap, templates, and junk

I keep running into annoying problems.

One is having macro conflicts. I like to just have stuff like


#define MIN(a,b)    ( (a) < (b) ? (a) : (b) )

for myself, which is fine and all, until you try to mix multiple codebases that all have their own idea of what that macro should be.

(obviously MIN is not actually a big deal because everybody agrees on what that should be; a bigger issue is like if people are doing a #define of malloc or SWAP or Log).

The cleanest thing I've come up with is :


1. All #defines in headers must be "namespaced" , like CB_MIN instead of just MIN.

2. Never #define anything that looks like it's in global namespace (eg. no #defining malloc)

3. Make a header called "use_cb.h" which does
    #define MIN     CB_MIN
    #define malloc  cb::malloc

    etc.

Basically this is hacky way of "namespacing" the macros and then "using the namespace" in the CPP files. Not awesome.


The other issue I'm running into is generic functions and template specialization.

Say you're working with some codebase, let's call it "stupidlib". They have their own ::swap template :


template < typename Type > inline void stupidSwap(Type &a,Type &b)
{
    Type c = a; a = b; b = c;
}

And then they also override it for some special cases :

template < >
inline void stupidSwap<stupidObject>(stupidObject &a,stupidObject &b)
{
    a.Swap(b);
}

Now, you are trying to munge stupidlib into a codebase that just uses the normal STL. It's putting objects in containers, and you want it to use std::swap correctly, but when you call std::swap on a stupidObject - it doesn't see that a nice swap override has been made.

So far as I can't tell you cannot fix this. It is impossible to make std::swap redirect to stupidSwap for the cases where stupidSwap has been overriden. You have to do it manually for each object type, and any time somebody changes stupidlib your code can silently break.

Now there is a pretty easy solution to this : never define a generic operation which already exists in the STL - just override the STL.

The problem is that people like to replace bits of the STL all the time. Hell I do it, because the STL headers are so retardedly bloated they kill compile times, so I try to use them minimally.

But that "solution" isn't really a solution anyway - it's just a convention to use the STL defs as bases for overloading when they exist. When you're trying to overload a generic operation that isn't defined in the STL you go back to having the same problem - two codebases can define that operation and various specializations, and you can't mix them.

Generic/template programming simply does not work well when mixing codebases.

No comments:

old rants