1

For example I have a function call in some code I want to be able to enable/disable as I like.

Normally I could just use an if, but then it would check each time if the function can be ran, which I don't want. I simply want the code to never do that check.

ifdef blocks can be messy and quite dirty, they pile up and make code hard to read.

Can't I solve this with some sort of template ? I know I can make multiple lambdas to build each version of the possible function call I'd want.

Is this what a static if means ? Because in my mind, what I want to do is a self modifying code, which I don't know if it's a good idea or possible at all.

jokoon
  • 6,207
  • 11
  • 48
  • 85
  • Since you asked multiple questions, I will answer the low hanging fruit. `"Is this what a static if means?"` [No, that is not what a static function is](http://stackoverflow.com/questions/558122/what-is-a-static-function?rq=1). – Cory Kramer Jul 11 '14 at 16:06
  • If you want it to decide at run-time, you will have to check at run-time. If it's at compile time, you could use a template, but it depends what you are doing. – Neil Kirk Jul 11 '14 at 16:08
  • Is this a compile time check? or is this a runtime check? Do you want to pass the option to the compiler? or to the executable? – Bill Lynch Jul 11 '14 at 16:12
  • Yes, it is called `if`. That is the thing that works at runtime. templated solutions like #ifdef work at compile-time. – dornhege Jul 11 '14 at 16:13
  • I guess he simply wants compile time decision without messy preprocessor code. – gexicide Jul 11 '14 at 16:14
  • @Cyber he is talking about [static if](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3329.pdf) and not about static functions. – PeterT Jul 14 '14 at 21:23
  • yes I want it at run time. basically I want to execute a function which does either something, nothing, or something else, without doing an if. I guess templates can do that but i'm not an expert in templates. – jokoon Jul 14 '14 at 21:34

4 Answers4

3

Assuming that this decision needs to be made at runtime...

While there are plenty of complicated solutions to this problem, a function pointer is a simple method (although I doubt that it's performance is significantly better than just the conditional).

#include <functional>
#include <iostream>

void option1(int) {
    std::cout << "option 1\n";
}

void option2(int) {
    std::cout << "option 2\n";
}

std::function<void(int)> fp(option1);

int main() {
    fp(3);

    // Let's change what fp does:
    fp = option2;
    fp(3);
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
2

If I have not misunderstood your question, I think you want something like the Strategy design pattern which is for runtime decision.

But just because you asked for a template, here is an example using Policy based template metaprogramming... But here, the decision is taken at compile time.

struct task {
    void do_task() { /* really do the task... */ }
};

struct no_task {
    void do_task() {} // empty
};

template<typename Task> class host : public Task {};

// here you take the decision...
// you can pass either task or no_task
host<task> h;

// and later you call the function...
h.do_task();

Using templates is really efficient.
There is no indirection through any pointer to function.
It is easy for compilers to inline the function.
If you pass it no_task, the call site won't even have a call to the empty function(check that out with your compiler's optimization levels).

Sam
  • 1,842
  • 3
  • 19
  • 33
  • so in the no task case, it will generate no code at all ? – jokoon Jul 11 '14 at 17:50
  • wait what is that "Task" class, do no_task and task inherit from them ? – jokoon Jul 14 '14 at 21:16
  • I tried both cases with gcc. With no optimization, it gives a call to the empty function. But with `-O2` optimization level, in the case of `host`, it inlined the function as expected. And in the case of `host`, it generated absolutely *no code* at the call site. – Sam Jul 16 '14 at 07:41
  • `host` is something that you instantiate and on its object you call the functions. `host` itself is empty. `Task` is the template parameter for `host`. While instantiating the `host` template, if you pass it `task`, it inherits `do_task` from `task` which actually implements the functionality. But if you pass it `no_task`, it is inherited from `no_task` and inherits `do_task` from `no_task` which does nothing. – Sam Jul 16 '14 at 07:47
  • Can I instantiate h of either host or host ? since I want to choose when starting my program, and then run it... – jokoon Jul 16 '14 at 19:24
1

You can use function overloading and a boolean template parameter:

template<bool B>
class X{
   // Function to be called when B is true
   void foo(std::true_type) {
      ..
   }
   // Function to be called when B is false
   void foo(std::false_type) {
        ... // leave empty to do nothing if B is false
   }



   void bar(){
      // This will call either of the foos depending on B
      foo(std::integral_constant<bool,B>());
   }

}

Explanation: The type trait std::integral_constant will either evaluate to a value of type std::true_type or std::false_type depending on whether B is true or false. This type will be used in overload resolution so the compiler will pick the right method for you. You can simply define one of the functions to be empty. This is like "disabling" the call when B is false, for example.

The decision which function to call is done at compile time, so you suffer no runtime overhead for this decision.

gexicide
  • 38,535
  • 21
  • 92
  • 152
1

Yes, there are ways to do what you want, but as they are runtime, they do infer a cost. As to whether what I give below is faster or slower than an if... You will have to profile and see. You pay for the dereference, but lose the extra branch.

Function pointers

You could solve this by having multiple versions of functions (or objects with virtual functions).

Example:

void stud(const char *) {}
void _log(const char *msg) { clog << msg << endl; };

void (*log)(const char *) = stud; 

void enable_logging()  { log = _log; }
void disable_logging() { log = stud; }

int main() {
    log("This will not be logged");
    enable_logging();
    log("This will be logged.");
}
Stian Svedenborg
  • 1,797
  • 11
  • 27