2

The problem i have that i have several functions that needs to be invoked in defined order the order can't be breakable. now the code need to be continued and develop after i finish to code. im looking for some method to set the functions in some kind of unbreakable structure. for example i have:

function_1() { //do some stuff ..} ;  // must be first  
function_2() { //do some stuff based on function_1()..};  // must be second 
function_3() { //do some stuff based on function_1() and function_2()..};;  // must be third 

they all under the main() app function .

user63898
  • 29,839
  • 85
  • 272
  • 514

5 Answers5

3

Create another function for public access, that guarantees the other three functions are called in the correct order. To prevent those functions are visible with the public API, you can hide them in an unnamed namespace.

In your header put

 bool function_4();

In your corresponding translation unit you create an unnamed namespace to prevent others from seeing those functions

 namespace {
     bool function_1() {
     }
     bool function_2() {
     }
     bool function_3() {
     }
 }

And define function_4

 bool  function_4() {
     return function_1() &&
            function_2() &&
            function_3();
 }
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
2

You can create a wrapping function

bool execute()
{
    return function_1() && function_2() && function_3();
}

The functions will be called in order, and it will short circuit if any of the functions fail. Assuming the functions return a bool indicating success/failure, if the function returns true all functions successfully completed, otherwise at least one of them failed.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • 2
    plus1 because this doesn't deserve a negative vote. anonymous downvoters on the loose again. – Cheers and hth. - Alf Feb 15 '15 at 14:57
  • This example shows bad approach to make predefined order of function execution. Compiler optimization can change order or even skip same functions in such logical expressions – VolAnd Feb 15 '15 at 14:58
  • 6
    @VolAnd The compiler would **absolutely not** change the order of this logical. The standard states that they must be called in exactly this order. And if the compiler skipped any functions, it would be the latter ones if an earlier one failed, which is "short circuiting behavior" which is **exactly what the OP wants**. – Cory Kramer Feb 15 '15 at 14:59
  • @Cyber Sorry, I have had to adopt your solution with my answer. I've been missing that "short circuiting behavior" point from OP's question. And of course you are right about it. – πάντα ῥεῖ Feb 15 '15 at 15:17
  • @Cyber : please explain, why you are so sure that any compiler with any optimization level in the expression `func_1() && func_2() && func_1() && func_3()` will call `func_1()` twice? – VolAnd Feb 15 '15 at 15:32
  • @VolAnd: Because the C++ spec says so. At least if `func_1()` isn't available for inspection by the compiler to determine that it has no side-effects. See for example the second example in my answerhere: http://stackoverflow.com/questions/28517041/if-else-if-ladder-and-compiler-optimization/28518085#28518085 - the compiler is not sure if `A()` and `B()` has no side-effects, so generates code to call them twice. However, if you do `func(func1(), func2(), func1())`, there is no guarantee which order the two calls to `func1` and the call to `func2` are made. – Mats Petersson Feb 15 '15 at 15:50
  • @Mats && Cyber : What exactly C++ standards said about calling functions in logical expressions? And would functions func_2 and func_3 be called after func_1 returns false? (refer to my example with `(func_1() && func_2() && func_1() && func_3() )` ) – VolAnd Feb 15 '15 at 16:03
  • @VolAnd [See here](https://stackoverflow.com/questions/628526/is-short-circuiting-boolean-operators-mandated-in-c-c-and-evaluation-order). There is a forced sequence point after the first expression. Therefore, even with "as-if" optimization, the compiler CANNOT change the order of evaluation in this logical. And no, once `func_1` returned false, nothing after that would execute after that, hence the "short-circuiting" behavior. – Cory Kramer Feb 15 '15 at 16:08
  • The standard guarantees that `func_2` and `func_1` and `func_3` are NOT called after the first call to `func_1` is made. I'm not going to quote the standard in a comment, but the standard guarantees that function calls are made if they have side effects, and it also guarantees short circuiting of logical and/or expressions, so if you do `if(ptr && ptr->x > 0) ...` it is guaranteed to NOT access `ptr->x` if `ptr` is 0. – Mats Petersson Feb 15 '15 at 16:09
  • "Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated." – Cory Kramer Feb 15 '15 at 16:10
  • @VolAnd The order is specified in **5.14 Logical AND operator**. – juanchopanza Feb 15 '15 at 16:10
  • Thanks for clarification of Cyber's idea. user63898 must make his functions bool – VolAnd Feb 15 '15 at 16:19
2

One hack you can try is to have function_1() return a type that only it can construct and then use this as a parameter to function_2()

class created_by_function_1 {
   created_by_function_1() { /* private constructor */ }
   friend created_by_function_1 function_1();
 };

created_by_function_1 function_1() { 
  // do stuff
  return created_by_function_1();
}

void function_2(created_by_function_1) {
} 

Now you can only use function_2 if you first called function_1.

auto proof = function_1();
function_2(proof); // OK

function_2(created_by_function_1()); // Compilation error

I would advise against using this :)

Motti
  • 110,860
  • 49
  • 189
  • 262
  • 2
    If you go one step further, you'll end up with a *fluent api style* 'myContext.function1().function2().function3()' – tofi9 Feb 15 '15 at 15:00
  • 1
    @tofi9 I assume the OP wants to have other stuff between invocations of his functions, otherwise why expose them separately (this is why I think he's not using the template method pattern) – Motti Feb 15 '15 at 15:01
  • 2
    There is one catch: nothing forces the client code to call all the functions. – Cheers and hth. - Alf Feb 15 '15 at 15:02
2

The simple case of ordering functions is to make a single function that is called by the user, that does all three of the subfunctions. However, this doesn't always work. The user may need to do some processing after function1 before calling function2. In that case, you need some kind of extra context, e.g.

class Context
{
   friend Function1, Function2, Function3;
   enum State 
   {
     f0, f1, f2, f3 
   } state;
public:
   Context() { state = f0; }
   ~Context() { if (state != f3) { ... may need to do stuff... }
}

void Function1(Context &ctxt)
{
   assert(ctxt.state == f0);
   ctxt.state = f1;
   ... 
}


void Function2(Context &ctxt)
{
   assert(ctxt.state == f1);
   ctxt.state = f2;
   ... 
}

void Function3(Context &ctxt)
{
   assert(ctxt.state == f2);
   ctxt.state = f3;
   ... 
}

int main()
{
   Context c;

   Function1(c);
   ...
   Function2(c);
   ...
   Function3(c);
   // c will be destroyed and check that state is f3.
}
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
2

I suppose that you have some solid reasons not to wrap all these three functions into one single function.

In this case the simplest approach, would be to manage a status that is shared between all the three functions:

static int function_status=0;    // shared status:  nothing was called 

function_1() { 
    if (status>0) 
       throw exception ("function_1 MUST be called first and only once");
    status=1;  // function_1 was called
    ...
}   
function_2() {
    if (status<1) 
       throw exception ("function_1 MUST be called before 2");
    else if (status>2) // I suppose function 2 could be called several times
       throw exception ("function_2 CANNOT be called after 3");
    status = 2;   
    ...
}
function_3() {
    if (status<2) 
       throw exception ("function_2 MUST be called before 3");
    else if (status==3) 
       throw exception ("function_3 CAN ONLY BE CALLED ONCE");
    status = 3; 
    ...
}

As you see, this status gives you the opportunity to check very precisely if the flow of execution respects the logic that you want.

Christophe
  • 68,716
  • 7
  • 72
  • 138