Template metaprogramming trick: Get the compiler to tell you what type you have

Raymond Chen

Raymond

C++ template metaprogramming is like writing a program in Prolog without a debugger. The compiler executes your metaprogram by running through a bunch of pattern-matching rules. But unlike Prolog, the C++ template metaprogramming language doesn’t have a debugger. You just feed your code to the compiler, and you get a few possible results:

  1. It fails to compile.
  2. It compiles and gives you what you want.
  3. It compiles and gives you something that wasn’t what you want.

Only if you’re lucky do you get case 2 on the first try.

There’s no way to single-step through your metaprogram, and there’s no print-debugging either. All you can do is see what the compiler says.

Here’s a trick I use to get something. It’s not great, but it’s still handy.

template<typename... Args> void whatis();

This is a forward declaration of a function that takes an arbitrary number of type arguments.

I can drop a call to this function at various points in my template metaprogram to see how the compiler deduced a type:

template<typename T>
void f(T&& t)
{
 whatis<T>();
 ... other stuff ...
}

When I instantiate f, a call to whatis<T> is made, among all the other stuff. I can look at the compiler output or the linker’s “unresolved external” error message to see what T ended up being.

double v = 3.0;
f(v);

// msvc

??$f@AEAN@@YAXAEAN@Z PROC                   ; f<double &>, COMDAT
        ... other stuff ...
        call    ??$whatis@AEAN@@YAXXZ       ; whatis<double &>
        ... other stuff ...
??$f@AEAN@@YAXAEAN@Z ENDP                   ; f<double &>

unresolved external symbol
"void __cdecl whatis<double &>()" (??$whatis@AEAN@@YAXXZ)

// gcc
_Z1fIRdEvOT_:
        ... other stuff ...
        call    _Z6whatisIJRdEEvv
        ... other stuff ...

undefined reference to `void whatis<double&>()'

Aha, in this instantiation of f, the type T was deduced to be double&.

It’s not a super-awesome trick, but with template metaprogramming, every little bit helps.

7 comments

Comments are closed.

  • Leif Strand
    Leif Strand

    This is the most profound blog entry you have ever written. I have bookmarked it. I think you have just taught me everything that I need to know about this metaprogramming thing. I might use this for inspiration in a future version of our product.

    The other day, I decided to resurrect MS InfoViewer as a (Django?) web site, complete with “Dr. GUI’s Espresso Stand” and everything. I’ll include your blog somehow — i.e., via scraping — if you don’t mind. It may take me a few years to write, as it will be be powered by the actual MFC app image running in a x86 emulator underneath, with the actual October 1996 MSDN CD-ROM images. Naturally, there will be CSS style sheets for that retro Windows look. What do you think? Will the lawyers come after me? Well, maybe I’ll just run it on my intranet. I just can’t stand MSDN nowadays. I don’t think they even call it that anymore. (Why do they break out the A/W versions of Win32 API functions separately nowadays, anyways?)

    “Time takes all but memories.”

  • Avatar
    Alex Alabuzhev

    There’s a better technique (by STL, popularised by Scott Meyers):

    template<typename...>
    class TD; // TD == "Type Displayer"
    ...
    TD<T> Type;

    The advantage is that you don’t have to wait for the linking phase – the compiler will complain straight away.