有没有标准的算法可以复制到?

Is There a Standard Algorithm to Copy Until?

我正在使用 istream_iterator<char> it,所以我无法反向迭代范围(或迭代两次,没有太多麻烦。)

我想复制直到满足条件。在标准库中有没有这样的东西:

copy_until(it, istream_iterator<char>(), ostream_iterator<char>(cout), [](const unsigned char i){ return isalpha(i); })

如果我必须滚动一些东西,我只是希望有一些我无法弄清楚的魔法。

编辑:

我希望从我的 copy_until 函数中得到的行为是:

while(it != istream_iterator<char>()) {
    if(!isalpha(static_cast<unsigned char>(*it))) break;
    cout << *it++;
}

开箱前没有副本。由于您是从 istream 复制的,因此除了使用带有 break 语句的循环之外别无选择。

http://en.cppreference.com/w/cpp/algorithm 为 C++ 中可用的所有算法提供了非常有用的参考(不仅是 算法库 中的算法,还有 Numeric, Memory, and CStd Libraries.) 以下是复制算法,即它们采用输入迭代器,输出迭代器和 lambda 作为参数:

  • copy_if "Copies the elements in the range, defined by [first, last)... Only copies the elements for which the predicate pred returns true"
  • transform "Applies the given function to a range and stores the result in another range."
  • remove_copy_if "Copies elements from the range [first, last), to another range beginning at d_first, omitting the elements which satisfy specific criteria"
  • replace_copy_if "Copies the all elements from the range [first, last) to another range beginning at d_first replacing all elements satisfying specific criteria with new_value"
  • unique_copy "Copies the elements from the range [first, last), to another range beginning at d_first in such a way that there are no consecutive equal elements... Elements are compared using the given binary predicate p"
  • partition_copy "Copies the elements from the range [first, last) to two different ranges depending on the value returned by the predicate p. The elements, that satisfy the predicate p, are copied to the range beginning at d_first_true. The rest of the elements are copied to the range beginning at d_first_false"
  • merge 需要 2nd 输入范围
  • set_difference 需要 2nd 输入范围
  • set_intersection 需要 2nd 输入范围
  • set_symmetric_difference 需要 2nd 输入范围
  • set_union 需要 2nd 输入范围
  • adjacent_difference "Computes the differences between the second and the first of each adjacent pair of elements of the range [first, last)... Differences are calculated using the given binary function op"
  • partial_sum "Computes the partial sums of the elements in the subranges of the range [first, last) and writes them to the range beginning at d_first... To sum up the elements, the second version uses the given binary function op."
  • exclusive_scan "Computes an exclusive prefix sum operation using binary_op for the range [first, last)"
  • inclusive_scan"Computes an inclusive prefix sum operation using binary_op for the range [first, last)"
  • transform_exclusive_scan "Transforms each element in the range [first, last) with unary_op, then computes an exclusive prefix sum operation using binary_op over the resulting range"
  • transform_inclusive_scan "Transforms each element in the range [first, last) with unary_op, then computes an inclusive prefix sum operation using binary_op over the resulting range"

因为lambda只是用来修改范围[first,last)的1:1赋值到d_firsttransformreplace_copy_if 和所有 数值库 算法都没有帮助(adjacent_differencepartial_sumexclusive_scaninclusive_scantransform_exclusive_scantransform_inclusive_scan。)

  • 如果满足 lambda 条件后,范围 [it, istream_iterator<char>()) 的剩余部分将直接复制到 2nd输出迭代器,partition_copy可以解决你的问题
  • 如果在满足 lambda 条件后 [it, istream_iterator<char>()) 范围的剩余部分将被一个函数迭代,这个函数可以被调用copy_if(或remove_copy_ifunique_copy)满足条件后的每个值
  • 但在一般情况下,您的问题的答案是标准算法不提供 "copy_until" 因此您需要使用 while-loop

只是为了完整性,因为标准没有提供开箱即用的解决方案,这就是我的解决方案:

template<class _InIt, class _OutIt, class _Pr>
inline void copy_until (_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
  while ((_First != _Last) && _Pred(*_First)) {
    *_Dest++ = *_First++;
  }
}

这就是我使用它的方式:

copy_until(std::istreambuf_iterator<char>(is),
           std::istreambuf_iterator<char>(),
           std::ostreambuf_iterator<char>(os), 
           [] (char c) { return <some usefull condition here> });

例如,从输入流中读取一个只有 alnum 字符的字符串:

std::istream& operator>> (std::istream& is, std::string& n) {
  std::ostringstream str;
  copy_until(std::istreambuf_iterator<char>(is),
             std::istreambuf_iterator<char>(),
             std::ostreambuf_iterator<char>(str), 
             std::isalnum);
  n = str.str();
  return is;
}

copy_until可以用std::find_if实现,std::copy.

使用与redleg相同的结构,算法可以先搜索终止符,然后复制范围。

template <class _InIt, class _OutIt, class _Pr>
inline void copy_until(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
    _InIt _posTerm = std::find_if(_First, _Last, _Pred);
    std::copy(_First, _posTerm, _Dest);
}

模板需要 <algorithm><iterator>.

这是一个如何使用它的例子:

std::vector<int> source = {1,2,3,4,5,6,7,8};
std::vector<int> dest {};

copy_until(source.begin(),source.end(), 
           back_inserter(dest),[](int c) {return c == 5;});

输出:

source: 1 2 3 4 5 6 7 8 
dest  : 1 2 3 4 

因为std::copy定义复制到最后,但不包括最后或其他术语[first,last)find_if的位置不复制。

如果您需要包含 until,意思是 [first,last],我们需要做更多检查。如果终止符在 end() 处,则不应推进迭代器。

template <class _InIt, class _OutIt, class _Pr>
inline void copy_until(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred)
{
    _InIt _posTerm = std::find_if(_First, _Last, _Pred);
    if (_posTerm != _Last ) { _posTerm++; }
    std::copy(_First,_posTerm,_Dest);
}

之前的例子现在输出:

source: 1 2 3 4 5 6 7 8 
dest  : 1 2 3 4 5