CppCon 2015: Fedor Pikus “C++ Metaprogramming: Journey from simple to insanity and back'

preview_player
Показать описание


Part I: Introduction to template metaprogramming. Template metaprogramming is a variant of generic programming, a technique that uses C++ template mechanism to perform computations at compilation time, usually to generate, from a single description, executable code that depends on the properties of the data types. It can be viewed as “programming with types”. In this example-driven class we start with the overview of the metaprogramming tools (everything you wanted to know about template specializations but were afraid to ask). We will apply these tools to simple examples, such as: how to sort a sequence in order of increasing values, unless it’s a sequence of pointers, in which case we want the values of what they point to. Part II: Advanced techniques and practical applications. Simple examples of metaprogramming are fun and useful, but once you master them you start chafing at the limitations. This is C++, where we don’t suffer limitations gladly. We therefore move on to the more advanced techniques, including SFINAE, and the appropriately more advanced examples. The journey takes us back to the beginning: after all, when sorting a sequence of values vs a sequence of pointers, you don’t really care whether the pointer is smart or dumb. What you really want to know is whether “*p” compiles or not. What you really need is an “if_compiles” metaprogramming function.

Fedor G Pikus is a Chief Engineering Scientist in the Design to Silicon division of Mentor Graphics Corp. His earlier positions included a Senior Software Engineer at Google, and a Chief Software Architect for Calibre PERC, LVS, DFM at Mentor Graphics. He joined Mentor Graphics in 1998 when he made a switch from academic research in computational physics to software industry. His responsibilities as a Chief Scientist include planning long-term technical direction of Calibre products, directing and training the engineers who work on these products, design and architecture of the software, and research in new design and software technologies. Fedor has over 25 patents and over 90 papers and conference presentations on physics, EDA, software design, and C++ language.


*-----*
*-----*
Рекомендации по теме
Комментарии
Автор

A simpler (albeit less educational) way to implement pow<N>():

template <int N> double pow(double x) {
// the following does the right thing for even and odd N
return pow<(N+1)/2>(x) * pow<N/2>(x);
}

template <> double pow<1>(double x) {
return x;
}

template <> double pow<0>(double x) {
return 1.0;
}

jcsahnwaldt
Автор

I think the trick he's doing is the following: If you want to calculate something like x^(2^k) it makes the compiler to multiply the answer per itself. Starting with x*x and then multiplying the result by itself gives us x^4 and so on.
About double's rounding errors (if I'm right) the less operations you make, the more reliable it is so this method will at least be as correct as the other (if not better)

martiangelatsiribera
Автор

For the computing x^N part, I have a shorter solution:
template<size_t N>
struct Pow
{
double operator()(double x) const
{
return Pow<N/2>()(x) * Pow<N - N/2>()(x);
}
};

template<>
struct Pow<1>
{
double operator()(double x) const
{
return x;
}
};

template<>
struct Pow<0>
{
double operator()(double x) const
{
return 1;
}
};


On my machine, it runs at least 5 times faster than the cmath version with optimization flags.

anhta
Автор

SFINAE @ 50:00: I think it should be "&U::sort" and not "&T::sort". Also, after NULL in the enum clause, there should be two closing parentheses, not just one

sakuranooka
Автор

The pow example is comparing apples to oranges: pow sets errno for floating point exceptions. And if you compile with -ffast-math or the equivalent you get just as fast (or faster) code with pow

Автор

On time 7:51, in the definition of IsAnyChar, there is no such thing in C++11 that requires the compiler to "guess" that we want to read the "type" type in "NoCV"! IMHO he meant:

template &lt;typename T>
struct NoCV { using type = T; };

template &lt;typename T>
struct NoCV&lt;const T> { using type = T; };

template &lt;typename T>
using NoCV_t = typename NoCV&lt;T>::type;

template &lt;typename T>
struct IsAnyChar {
constexpr static bool value =
};

AkimDemaille
Автор

I think there is a typo in the slide at minute 24:00, x*Pow<N/2>()(x) has an N/2 instead of (N-1)/2 as previously displayed in the "For odd N we need:" example above

MarcusAseth
Автор

how is x8*x8 better than x16? The generated codes are both 16 xs multiply.

beijia
Автор

On time 34:25, he shifts T(1) (possible int) and does bit mask operations with it. Is it legal to do shifts and bit-wise operations with signed types?

MarekKnapek
Автор

On time 21:50 he says that `x^16` (where `x` is run-time `double` and `16` is compile-time known constant) can be computed faster as `x^8 * x^8` instead of `x*x*x*x*...*x`.

It may or may not be true because of rounding issues and numerical stability. Rounding modes (towards zero, even, ...) can be changed at run-time.

MarekKnapek
Автор

log2(5) = 2? Compute log2(5) using the algorithm shown at 11:51

The simpler version of Log2 he showed computes log2(5) = 3

vonkruel
Автор

Mammoth-old shit techniques. You don't have to do almost all of what he does. (Ignoring his wrong code in pow section.)

xFD
Автор

Yeah, I stared at that slide for a few minutes before realizing the slide was the problem & not my failure to grok it. His "fast" version of pow2 is also incorrect (despite his assertion). 12 minutes in, and 2 glaring mistakes already... talk aborted.

vonkruel