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

Raymond Chen

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)
 ... 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;

// 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
        ... 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.


Discussion is closed. Login to edit/delete existing comments.

  • Alex Alabuzhev 0

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

    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.

    • Raymond ChenMicrosoft employee Author 0

      I prefer to wait until the linking stage, because that lets me see two things at once: Whether the code would have compiled, and what the type is. I use this technique mostly on gcc.godbolt.com.

      • Erkin Alp Güney 0

        I thought you were not allowed to mention anything non-Microsoft by mentioning brand names in this blog.

  • Letao Wang 0

    Holding my breath for someone to implement a meta-debugger for template metaprogramming, using template metaprogramming.

  • Leif Strand 0

    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.”

  • Brian MacKay 0

    It might be handy to include a link to an MSVC demangler (like http://demangler.com/) so that folks can demangle `??$whatis@AEAN@@YAXXZ` into a more readable type `void __cdecl whatis<double & __ptr64>(void)`

    • Raymond ChenMicrosoft employee Author 0

      The compiler undecorates it for you in the comment, as I noted. If you really want to undecorate it yourself, you can use the undname program that comes with Visual Studio.

Feedback usabilla icon