只能由函数本身写入的函数参数 - 递归计数器

问题描述 投票:4回答:5

所以我正在尝试编写一个递归函数来跟踪它被调用的频率。由于它的递归性质,我将无法在其中定义迭代器(或者可能通过指针?),因为每当函数被调用时它都会被重新定义。所以我想我可以使用函数本身的参数:

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

现在我面临的问题是,counter可以被函数的调用者写入,我想避免这种情况。再说一遍,将counter宣布为const无济于事,对吧?有没有办法将变量的操作限制为函数本身?或者也许我的方法在一开始就存在严重缺陷?

我能想到解决这个问题的唯一方法是使用一种“包装函数”来跟踪调用递归函数的频率。

我想避免的一个例子:

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

使用我的功能的用户不应该初始设置计数器(在这种情况下为10)。

c++ recursion
5个回答
3
投票

您可以按原样运行,并将其包装。我想到的一种方法是完全封装包装,这是通过使你的函数成为本地类的静态成员。展示:

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);
}

本地类是C ++的一个漂亮但很少见的特性。它们有一些限制,但幸运的是可以有静态成员函数。没有来自外部的代码可以传递hidden::countRecursive无效的counter。它完全在countRecursive的控制之下。


2
投票

如果你可以使用其他东西而不是自由函数,我建议使用某种仿函数来计算,但如果你不能,你可以尝试使用友谊来做这样的事情:

#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);
}

1
投票

你可以封装counter

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

现在调用者无法修改计数器,您只需要稍微修改一下这个函数:

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

隐式转换允许您使用int调用它

counterRecursive(5);

1
投票

一种方法是使用仿函数。这是一个简单的例子:

#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;
}

输出:

Result: 13
Number of calls: 107

由于计数存储在对象本身中,因此用户无法覆盖它。


-3
投票

您是否尝试过使用“静态”计数器变量。静态变量只被初始化一次,并且是用作计数器变量的最佳候选者。

© www.soinside.com 2019 - 2024. All rights reserved.