4

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).

Paez Rice
  • 75
  • 2
  • 6
  • 1
    C [doesn't have default arguments](https://stackoverflow.com/questions/1472138/c-default-arguments), so your question is about C++. – ForceBru Apr 14 '19 at 10:47
  • 1
    Yes I would say a wrapper function is the way to go here. – Galik Apr 14 '19 at 10:48
  • Maybe you could use a static variable ? – Maxime Apr 14 '19 at 10:50
  • @ForceBru thanks for noting that, I edited the title accordingly – Paez Rice Apr 14 '19 at 10:51
  • Better yet, tags are to specify the language. Common SO practice is to not mention the language in the title at all, but in the tags only – StoryTeller - Unslander Monica Apr 14 '19 at 10:53
  • @Maxime sure this would be a way to go about it. Or even calling a variable that's declared outside of the function's scope by reference. However the question I have is less about solving the problem itself in any way possible, but solving it in a manner where the function handles the tracking itself. – Paez Rice Apr 14 '19 at 11:00

5 Answers5

3

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.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    I really didn't expect to see a solution to this that I actually liked but this isn't half bad - especially for inline functions where the internal function is harder to hide. – Galik Apr 14 '19 at 11:50
  • While I _do_ like some of the other answers as well, and like the "thought-work" that got put into them, I think your solution might be the most straight forward one for my problem. Thanks a lot, everyone. – Paez Rice Apr 14 '19 at 13:01
  • I agree, I keep my answer for documentation, but I agree that this one is far better. – OznOg Apr 14 '19 at 19:01
2

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);
}
OznOg
  • 4,440
  • 2
  • 26
  • 35
1

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);
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

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.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
-3

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

dennis
  • 680
  • 1
  • 5
  • 11
  • 5
    `static` is a terrible solution. The function won't work correctly the second time you call it, and won't be thread-safe – interjay Apr 14 '19 at 10:58