Search code examples
c++templatescompilationmetaprogramming

How really distinguish compile time and run time information?


This question might seem broad, but it really isn't.
More specifically, if we are using templates, how do we distinguish what is compile time information and run time information?

I was watching CppCon video on the optimization and HFT systems and came across this example. If you are not familiar with high frequency trading systems, and insight is that they are really trying to squeeze the last few nanosecond from the benchmark, often violating the classy OOD principles in order to gain performance.

The example I want more to elaborate on is the following:

template<Side T>
void Strategy<T>::run()
{
    const float orderPrice = calcPrice(fairValue, credit);
    //....
    sendOrder(orderPrice);
}

template<>
float Strategy<Side::buy>::calcPrice(float value, float credit)
{
    return value - credit;
}

template<>
float Strategy<Side::sell>::calcPrice(flaot value, float credit)
{
    return value + credit;
}

According to the author, this example illustrates a classical way of avoiding the run time if-else branching.
But at the time of compilation, we don't really know whether we are going to buy or cell right? The decision is made during the run time depending on market movement.
Can someone please explain how the link between run time and compile time, specifically, how we are creating a compile time branching depending on the run time information?


Solution

  • You're right on the general principle: at compile time, you won't know whether to sell or buy. That's going to take an if-statement.

    However, the technique used there is still useful when the single if-statement to control buy/sell controls two large blocks of similar code. You can now write out those blocks explicitly (code duplication), write it once but repeat the if-statement for all the parts where the two blocks would diverge (slow), or use templates to have the compiler generate two blocks of code for you.

    I have a even better example in my own code base, where I use a switch outside to choose one of 7 template instantiations. Each template instantiation is a loop over hundreds of elements, and the switch outside means I don't have the switch inside the loop. Sure, I have 7 template instantiations, but RAM is cheap.