Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are common culprits for TMP slowness

I have a project which uses quite a bit of C++ template meta-programming. This makes compile times long. I understand that I cannot have the cake and eat it too but I would like to know some tips and tricks on how to reduce compile times. I have already tried explicit instantiations and while that might help in some cases, a lot of the times, the instances are unique to a particular compilation unit in which case explicit instantiation does nothing to help. And now we're only talking about Clang which does a pretty good job. When I try this on G++, the compile time just explodes. For one file, I gave up waiting for it to compile after 45 minutes.

  • Are there any common culprits when it comes to template meta-programming, things that are known to often be problematic? What techniques should I avoid and what should I do instead?
  • Are there any areas where GCC is known to perform worse than Clang and is there any way to work around this?

I'm using mostly plain vanilla C++11 techniques, I don't use Boost MPL or similar libraries.

like image 391
Emil Eriksson Avatar asked Apr 20 '15 20:04

Emil Eriksson


1 Answers

Here are some advises regarding metaprogramming with C++11 and beyond:

  • Prefer variadic expansion based algorithms. Variadic templates are usually handled quickly by the compiler compared to the O(n) chain of template instantiations one usually need for typelists and related on old C++98/03. I'm eager to see C++1z fold expressions, as a way to implement fold family metafuntcitons using pack expansion.

  • Avoid inheritance chains: Algorithms based on recursive inheritance usually perform badly since the compiler should track the inheritance tree metadata. Prefer raw calls to next ::type instead of inheriting directly from the next "call" as a shorthand to get that type member.

  • Prefer inheritance pack expansion to recursive inheritance: That is, if you are implementing a tuple like thing, prefer

    template<typename... Ts>
    struct tuple : Ts...
    

    to

    template<typename Head, typename... Tail>
    struct tuple : Head, tuple<Tail...>
    

    since the compiler should intantiate N subtypes on the latter, plus the inheritance overhead described at point above.

  • Prefer name lookup based algorithms: Name lookup usually performs faster than recursive template instantiation. So, consider doing something like decltype(declval<T>().f()) to compute a type, where the result is in the correct f overload.

like image 120
Manu343726 Avatar answered Nov 02 '22 16:11

Manu343726