docp
docp

Reputation: 327

How to call function member with different argument several times?

My class has function that follows simple pattern, yet I don't know if there is a way to avoid code duplication so it will be much shorter. Here is simplified example:

class Data
{
public:
    void compute()
    {
        if (procedure1)
        {
            runAlpha(param1);
            runAlpha(param2);
            runAlpha(param3);
        }
        if (procedure2)
        {
            runBeta(param1);
            runBeta(param2);
            runBeta(param3);
        }
        if (procedure3)
        {
            runGamma(param1);
            runGamma(param2);
            runGamma(param3);
        }
    }
}

runAlpha, runBeta, runGamma are also public members of this class. As you see, there is very little difference between each procedure and also between run calls. I would like to simplify this code a little bit, but im not allowed to modify run functions, so I thought about using templates. However, adding the callMultipleRuns method to class and replacing body of if statement doesn't compile.

template <typename Run>
void callMultipleRuns(Run r)
{
    r(param1);
    r(param2);
    r(param3);
}

void compute()
{
    if (procedure1)
        callMultipleRun(runAlpha);
    if (procedure2)
        callMultipleRun(runBeta);
    if (procedure3)
        callMultipleRun(runGamma);
}

The error is error: invalid use of non-static member function. I cannot add static to run declaration. Is there a way to fix it?

Upvotes: 2

Views: 61

Answers (2)

JHBonarius
JHBonarius

Reputation: 11281

Firstly, you found that you cannot simply pass a non-static member function as a parameter. However you can pass a reference to the member function. This must be in a specific form, as specified by the standard.

Some example code

#include <cstdio>
class Data {
public:
    void runAlpha(int i) { printf("a%d", i); };
    void runBeta(int i) { printf("b%d", i); };
    void runGamma(int i) { printf("c%d", i); };

    template <typename Run>
    void callMultipleRuns(Run r)
    {
        (this->*r)(1);
        (this->*r)(2);
        (this->*r)(3);
    }

    void compute()
    {
        if (true) callMultipleRuns(&Data::runAlpha);
        if (true) callMultipleRuns(&Data::runBeta);
        if (true) callMultipleRuns(&Data::runGamma);
    }
};

int main() {
    Data{}.compute();
}

on Godbolt

Upvotes: 1

Botje
Botje

Reputation: 31020

You're close, but you cannot use runAlpha and friends as standalone functions like that; they need an instance.

Luckily, the C++ standard library has helpers for this.
The first is simply to pass a lambda function:

callMultipleRuns([=](auto param) {runAlpha(param);})

or use std::bind:

callMultipleRuns(std::bind(&Data::runAlpha, this, std::placeholders::_1);

Upvotes: 0

Related Questions