Using pointers to struct members in template functions

 

After encountering a need to implement functional analysis indicators, I’ve encountered a problem: I have two structures which I am actively using to store market data (simplified version is given here):

Candle is used to store the market data for each period of time (for example, every 30 minutes):


struct Candle
{
    double open;
    double close;
    double high;
    double low;
};

 

RangeBar is used to focus only on price fluctuations, it has constant height (therefore we do not need to know the open price and store the height separately: it is usually stored as a system constant)


struct RangeBar
{
    double close;
    bool is_rising;
};

 

What should be done if I want to calculate Simple Moving Average(or simply SMA) value of 20 consequtive candle high or open prices? What if I want to calculate RangeBar close prices? Should I declare 3 functions for every one of them?

One of the possible solutions would be to implement a common class for both RangeBar and Candle, which has virtual Getter methods. However, a colleague of mine has suggested an alternative, much more elgant solution, using C++ templates with pointers to struct members as a template arguments.

Therefore, an SMA function will look like this:


template <typename T, double T::*member> double SMA(T* values, size_t length)
{
    double sum = 0;
    for (size_t i = 0; i < length; i++)
    {
        sum += values[i].*member; //make sure to dereference the member pointer
    }
    return sum / length;
}

 

Then, when I want to calculate the SMA, I just need to call the function with correct parameters. For example:


    double sma_close_range_bars = SMA<RangeBar, &RangeBar::close>(bars, bar_amount);
    double sma_high_candles = SMA<Candle, &Candle::high>(candles, candle_amount);
    double sma_low_candles = SMA<Candle, &Candle::low>(candles, candle_amount);

 

Voila. Now we have a universal solution for this type of problems.

Leave a Reply

Your email address will not be published. Required fields are marked *