A year or so back I had a brief look at Alexandrescu's "Modern C++ Design". As I have reasonably extensive experience of the "xTL trilogy" of ATL, WTL & STL I had considered myself a fairly advanced user (or possibly abuser in ATL's case ;) of C++ templates, and had even written a CodeProject article on a particular pattern of usage of them. Despite all this though, the book was a complete eye-opener as to just how powerful a construct C++ templates are. I skipped a lot of the more complex material in the book, mainly as it involved the use of "partial template specialisation", which is not supported by VC++ 6. However, now that VC++ 2003 is freely downloadable, I may well have to revisit it.

Anyway, enough about template meta-programming in general, and on to the point of this post. One of the early examples in the book is that of compile-time assertion. A simplified version appears below:

    template struct CtAssert;
    template<> struct CtAssert {} ;

    #define CT_ASSERT(cond) CtAssert()

    int main(int argc, char* argv[])
    {
        CT_ASSERT(sizeof(int) <= sizeof(long));   // compiles ok
        CT_ASSERT(sizeof(wchar_t) == 1)           // gives error

        return 0;
    }

This works because there is an specialised implementation for the case where the template argument is 'true', but no implementation, specialised or generic, when it is false. This therefore causes an error, which the more sophisticated code in the book "arranges" to be somewhat more indicative of the cause than my code above.

What's prompted the sudden reignition of my interest, you may ask? Well, recently I've been doing quite a bit with macros and had a few versioning issues where I'd updated a macro definition but not all of the usages of it. It struck me this morning that I could pull a similar compile-time trick to type check the arguments to a macro, in the cases where it would make sense to do so.

    template <typename T>
    struct CtTypeCheck
    {
        CtTypeCheck(const T&) {}
    };

    #define CT_TYPE_CHECK(test, type) CtTypeCheck<type> dummy_##test(test)

    int main(int argc, char* argv[])
    {
        int a, b;
        CT_TYPE_CHECK(a, int);    // compiles ok
        CT_TYPE_CHECK(b, void*);  // gives error

        return 0;
    }

This will clearly take implicit conversions into account when testing, but that's probably OK in most scenarios.