-1

I am writing a program where the user can set option flags at the beginning.

My problem is that I want to call different versions of a function based on user flags, and I don't want to have to do if(flag) every time I am picking which version to call because I would have to check the if() statement on every line I process.

This is a school project so I'm trying to find the most efficient way of determining which function I want to call, and I readif()` statements are expensive here.

So is there is there a way to essentially say at the beginning

if(flag)
  // use this function the rest of the program
else
  // use this other function for the rest of the program
user0042
  • 7,917
  • 3
  • 24
  • 39
Kilbo
  • 333
  • 1
  • 12
  • 1
    On modern computers, you will need an quantum clock to be able to measure a simple `if()` statement. Move on to more important things. – Sam Varshavchik Oct 11 '17 at 01:06
  • _"I don't want to have to do if(flag) ..."_ Well, use a `std::map> fnmap;` and call `fnmap[flag](...);` then.. But it won't be really more _efficient_ at least. Another option is to decide for a `std::function` variable once, and use that subsequently. – user0042 Oct 11 '17 at 01:07
  • 1
    "and I read if statements are expensive" - where did you read that? –  Oct 11 '17 at 01:08
  • here https://stackoverflow.com/questions/315306/is-if-expensive – Kilbo Oct 11 '17 at 01:09
  • @Kilbo And you understood what _cache inlining_ actually is? – user0042 Oct 11 '17 at 01:11
  • 1
    @drescherjm A `std::function` variable rather ... – user0042 Oct 11 '17 at 01:12
  • @user0042 to be honest not really, I thought that I kind of got the gist of it but I did some more reading and I see now that if my if statement branches the same way all 100,000 lines of input it's not actually going to slow down my code in any measurable way. – Kilbo Oct 11 '17 at 17:44
  • @Kilbo Well, the solution from my answer will at least simplify your code a lot. – user0042 Oct 11 '17 at 17:45
  • @user0042 it definitely will, thank you! – Kilbo Oct 11 '17 at 18:06

3 Answers3

6

so if theres a way to essentially say at the beginning if(flag) use this function the rest of the program else use this other function for the rest of the program

Just do something like follows:

void func1() {
    // ...
}

void func2() {
    // ...
}

int main(int argc, char* argv[]) {
    std::function<void()> func;

    // Make your decision once:
    if(std::string(argv[1]) == "func1") {
        func = func1;
    }
    else if(std::string(argv[1]) == "func2") {
        func = func2;
    }

    // Call func many times
    func();

    // ...
}
user0042
  • 7,917
  • 3
  • 24
  • 39
  • I'd be very surprised if this is actually faster than a branch that is always taken the same way. – Nir Friedman Oct 11 '17 at 01:49
  • Is this considered good style? Or is the fact that I'm in this situation at all a sign of bad code development. – Kilbo Oct 11 '17 at 17:23
  • @Kilbo Looks fine for me, what are your concerns actually? – user0042 Oct 11 '17 at 17:27
  • I'm a pretty novice coder, learning at university right now only on my 3rd semester classes. The class i'm in right now puts a lot of emphasis on being efficient and using very little memory. I had read that if statements were expensive as I said above although people in the comments seemed to tear me apart for that. My thought was that if I could just define which function I wanted at the beginning i'd avoid an if check for every single line of code I input and this looks like a perfect solution. – Kilbo Oct 11 '17 at 17:40
1

You can use the old style array of function pointers like follows:

#include <stdio.h>

int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int (*p[4]) (int x, int y);

typedef enum{
    SUM=0,
    SUB,
    MUL,
    DIV
}FLAG;

int main(void)
{
  int result;
  int i, j, op;

  p[SUM] = sum; /* address of sum() */
  p[SUB] = subtract; /* address of subtract() */
  p[MUL] = mul; /* address of mul() */
  p[DIV] = div; /* address of div() */

  printf("Enter two numbers: ");
  scanf("%d %d", &i, &j);

  printf("0: Add, 1: Subtract, 2: Multiply, 3: Divide\n");
  do {
    printf("Enter number of operation: ");
    scanf("%d", &op);
  } while(op<0 || op>3);

  result = (*p[op]) (i, j);
  printf("%d", result);

  return 0;
}

int sum(int a, int b)
{
  return a + b;
}

int subtract(int a, int b)
{
  return a - b;
}

int mul(int a, int b)
{
  return a * b;
}

int div(int a, int b)
{
  if(b) 
      return a / b;
  else 
      return 0;
}
James Dong
  • 404
  • 3
  • 7
  • Why function pointers over `std::function`? Why `printf()` / `scanf()`? OP asked for c++ solutions. – user0042 Oct 11 '17 at 01:39
0

The best way to do this sort of thing is to use templates. Your problem can be understood to be similar to the "loop pullout" problem:

void foo(vector v, bool b) {
    for (auto e : v) {
        // do stuff
        if (b) // stuff
        else // other stuff
        // do more stuff
    }
}

The branch doesn't change during the loop, but we keep hitting it. It's surprisingly hard to rewrite this elegantly, especially if there's a bunch of code before and after the branch. With templates, we can use this approach:

template <bool b>
void foo(vector<double>& v) {
    for (auto e : v) {
        // do stuff
        if (b) // stuff
        else // other stuff
        // do more stuff
    }
}

void foo(vector<double>& v, bool b) {
    if (b) foo<true>(v);
    else foo<false>(v);
}

Internally the compiler will generate two versions of foo, one where the bool is hardcoded true at compile time, and the other will it is hardcoded false at compile time. In each case, the compiler will have no trouble eliminating the branch completely. Then you just dispatch to the correct function at the beginning of the call, branching only once. But the structure of your code is exactly the same; you just add a few lines of code that will not increase as your loop gets bulkier.

Nir Friedman
  • 17,108
  • 2
  • 44
  • 72