Paez Rice
Paez Rice

Reputation: 75

function parameters that are writeable only by the function itself - recursion counter

So I'm trying to write a recursive function that keeps track of how often it got called. Because of its recursive nature I won't be able to define an iterator inside of it (or maybe it's possible via a pointer?), since it would be redefined whenever the function gets called. So i figured I could use a param of the function itself:

int countRecursive(int cancelCondition, int counter = 0) 
{
    if(cancelCondition > 0)
    {
        return countRecursive(--cancelCondition, ++counter);
    }
    else
    {
        return counter;
    }
}

Now the problem I'm facing is, that the counter would be writeable by the caller of the function, and I want to avoid that. Then again, it wouldn't help to declare the counter as a const, right? Is there a way to restrict the variable's manipulation to the function itself? Or maybe my approach is deeply flawed in the first place?

The only way I can think of solving this, is to use a kind of "wrapper-function" that keeps track of how often the recursive function got called.

An example of what I want to avoid:

//inside main()
int foo {5};
int countToZero = countRecursive(foo, 10);
//countToZero would be 15 instead of 5

The user using my function should not be able to initially set the counter (in this case to 10).

Upvotes: 4

Views: 263

Answers (5)

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29965

One way to do this is to use a functor. Here's a simple example:

#include <iostream>

class counter
{
public:
  unsigned operator()(unsigned m, unsigned n) 
  {
    // increment the count on every iteration 
    ++count; 

    // rest of the function
    if (m == 0) 
    {
      return n + 1;
    }
    if (n == 0) 
    {
      return operator()(m - 1, 1);
    }
    return operator()(m - 1, operator()(m, n - 1));
  }

  std::size_t get_count() const
  {
    return count;
  }

private:
  // call count
  std::size_t count = 0;
};


int main()
{
  auto f  = counter();
  auto res = f(4, 0);
  std::cout << "Result: " << res << "\nNumber of calls: " << f.get_count() << std::endl;
  return 0;
}

Output:

Result: 13
Number of calls: 107

Since the count is stored in the object itself, the user cannot overwrite it.

Upvotes: 1

You can take you function as is, and wrap it. One way I have in mind, which completely encapsulates the wrapping is by making your function a static member of a local class. To demonstrate:

int countRecursive(int cancelCondition) 
{
    struct hidden {
        static int countRecursive(int cancelCondition, int counter = 0) {
            if(cancelCondition > 0)
            {
                return countRecursive(--cancelCondition, ++counter);
            }
            else
            {
                return counter;
            }
        }
    }; 
    return hidden::countRecursive(cancelCondition);
}

Local classes are a nifty but rarely seen feature of C++. They possess some limitations, but fortunately can have static member functions. No code from outside can ever pass hidden::countRecursive an invalid counter. It's entirely under the control of the countRecursive.

Upvotes: 3

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122228

You can encapsulate the counter:

struct counterRecParam {
    counterRecParam(int c) : cancelCondition(c),counter(0) {}
    private:
    int cancelCondition;
    int counter;
    friend int countRecursive(counterRecParam);        
};

Now the caller cannot modify the counter, and you only need to modify the function slightly:

int countRecursive(counterRecParam crp) 
{
    if(crp.cancelCondition > 0)
    {
        --crp.cancelCondition;
        ++crp.counter;
        return countRecursive(crp);
    }
    else
    {
        return crp.counter;
    }
}

And the implicit conversion lets you call it with an int

counterRecursive(5);

Upvotes: 1

OznOg
OznOg

Reputation: 4722

If you can use something else than a free function, I would suggest to use some kind of functor to hold the count, but in case you cant, you may try to use something like this using friendship to do the trick:

#include <memory>

class Counter;
int countRecursive(int cancelCondition, std::unique_ptr<Counter> counter = nullptr);

class Counter {
    int count = 0;
private:
    friend int countRecursive(int, std::unique_ptr<Counter>);
    Counter() = default; // the constructor can only be call within the function
                         // thus nobody can provide one
};

int countRecursive(int cancelCondition, std::unique_ptr<Counter> c)
{
    if (c == nullptr)
       c = std::unique_ptr<Counter>(new Counter());

    if(cancelCondition > 0)
    {
        c->count++;
        return countRecursive(--cancelCondition, std::move(c));
    }
    else
    {
        return c->count;
    }
}

int main() {
    return countRecursive(12);
}

Upvotes: 2

dennis
dennis

Reputation: 700

Have you tried using "static" counter variable. Static variables gets initialized just once, and are best candidates to be used as counter variables.

Upvotes: -3

Related Questions