递归传递一个字符串而不重新创建

时间:2015-03-12 10:51:08

标签: c++ string recursion construction char-pointer

我在这里回答了一个问题:https://stackoverflow.com/a/28862668/2642059我需要使用重复来逐步执行string。我想在每个函数上使用const string&作为我的参数,但除非我想重建每个递归的字符串,否则我发现我需要传递startfinish位置以及string本身。因此,传递string毫无意义。

最后,我选择将startfinish指针传递给char[]


作为一个例子,假设我给了一个包含嵌套括号的字符串(但没有并排的括号插入。)所以这样:

  

(ABC(DEF(GHI((j)的KLM)NOP)QRS)TUV)WXYZ

但不是这样的:

  

(ABC(DEF)(GHI)(J)(KLM)(NOP)(QRS)TUV)WXYZ

我想编写一个递归程序来在最深的嵌套括号中提取字符串。类似的东西:

string foo(const string& bar){
    auto start = bar.find('(') + 1;

    return start == string::npos + 1 ? bar : foo(bar.substr(start, bar.find_last_of(')') - start));
}

然而,我很不高兴为string的每次重复重建foo。另一种方法是传递startfinish指针,如链接示例中所示(或传递string::const_iterator s。)

是否有包装或某些内容可以让我使用string功能,但不会重建string

2 个答案:

答案 0 :(得分:3)

来自库基础知识TS的{p> string_view可能是一个想法,GCC中提供了支持。

界面几乎与string

相同
#include <experimental/string_view>
using std::experimental::string_view;

string_view foo(const string_view& bar){
    auto start = bar.find('(') + 1;

    return start == string_view::npos + 1 ? bar : foo(bar.substr(start, bar.find_last_of(')') - start));
}

最后一行也可以是

return start ? foo(bar.substr(start, bar.find_last_of(')') - start)) : bar;

虽然他们都非常神秘。

答案 1 :(得分:1)

编写自己的array_view<T>。这是几十行代码。

使用std::find替换这两种算法。在一种情况下,使用反向迭代器。 (或写一个基于范围的查找和基于范围的backwards

使用{T*,T*} ctor递归。

array_view<const char> foo(array_view<const char> bar)

这是一个原始array_view<T>

template<class T>
struct array_view {
  using mutable_T = typename std::remove_reference<T>::type;
  // 3 primitive functions:
  T* begin() const { return b; }
  T* end() const { return e; }
  array_view(T* s, T* f):b(s), e(f) {};
  // everything else based on them:
  size_t size() const { return end()-begin(); }
  array_view(T* s, size_t l):array_view(s,s+l) {}
  array_view():array_view(nullptr,  nullptr) {}
  // repeat next 3 for string, array, initializer list, C array as required:
  template<class A>
  array_view( std::vector<T,A>& v ):array_view(v.data(), v.size()) {}
  // may not compile for non-const T, but that is ok  you get an error:
  template<class A>
  array_view( std::vector<mutable_T,A>const & v ):array_view(v.data(), v.size()) {}
  // in a better world, you'd SFINAE remove the above from consideration
  // consider it for your next iteration of array_view.
  // conversion to containers:
  template<class A>
  explicit operator std::vector<mutable_T,A>() const {
    return convert_to< std::vector<mutable_T, A> >();
  }
  template<class C>
  C convert_to() const {
    C retval(begin(), end());
    return retval;
  }

  // utility functions:
  T& front() const { return *begin(); }
  T& back() const { return std::prev(*end()); }
  // Also rbegin, rend, and whatever else you find you are missing

  // inspired by std::experimental:
  void pop_front() { *this = {std::next(begin()), end()}; }
  void pop_back() { *this = {begin(), std::prev(end())}; }
  // but I find direct use of `view = {x,y}` almost as good
  // these kind of operations are the ONLY ones that are non-const
  // remember this is a view.  If you want a view of const data, make it
  // an array_view<const T>, not a const array_view<T>.  It really works
  // out better.
private:
  T* b
  T* e;
};

以上示例代码未经过测试。