std::将n个元素或复制到末尾



我想复制最多N个元素。

template< class InputIt, class Size, class OutputIt>
OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result)
{
    Size c = count;
    while (first != last && c > 0) {
        *result++ = *first++;
        --c;
    }
    return result;
}

有没有办法用std函数做到这一点?我也可以:

template< class InputIt, class Size, class OutputIt>
OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result)
{
    if(std::distance(first, last) > count)
        return std::copy_n(first,count,result);
    return std::copy(first,last,result);
}

然而,除了繁琐之外,它还可以两次越过范围(距离、副本)。如果我使用的是转换迭代器或过滤器迭代器,那么这些都是对我的过滤器/转换函数的O(N)不必要的调用。

template <class InputIt, class OutputIt>
OutputIt copy_n_max(InputIt begin, InputIt end, OutputIt last, size_t count)
{
    return std::copy_if(begin, end, last, 
                        [&count](typename std::iterator_traits<InputIt>::reference)
                        { return count--> 0; });
}
int main()
{
    std::vector<int> v({1,2,3,4,5,6,7,8,9}), out;
    copy_n_max(v.begin(), v.end(), std::back_inserter(out), 40);
    for(int i : out) std::cout <<i << " ,";
}

输出1,2,3,4,5,6,7,8,9,

然而,这将持续到最后,并且不计算次数。所以,还有更多不必要的对我的filter/transform函数的调用。。。

如果您可以访问整个数据结构,从而访问其大小,则可以使用以下内容:

std::vector<int> v1, v2;
std::copy_n(v2.begin(), std::min(NUM, v2.size()), std::back_inserter(v1));

如果你只能访问迭代器,我不知道如何在不计算距离的情况下只使用std函数来实现这一点。这对于随机访问迭代器来说很便宜,但对于其他类型来说是重复的。

std::vector<int>::iterator i_begin, i_end, o_begin;
std::copy_n(i_begin, std::min(NUM, std::distance(i_begin, i_end)), o_begin);

我会选择这样的东西:

template <class InputIt, class OutputIt>
OutputIt copy_n_max(InputIt begin, InputIt end, OutputIt last, size_t count)
{
    return std::copy_if(begin, 
                        end, 
                        last, 
                        [&count](typename std::iterator_traits<InputIt>::reference) -> bool 
                        {
                            if (count > 0)
                            {
                                --count;
                                return true;
                            }
                            return false;
                        });
}

使用copy_if谓词检查是否复制了足够的此输入。我在这里看到的主要优势是不涉及额外的std::distance

IDEOne 上的实时示例

有一种简单的方法可以使用C++11为您的任务添加的std::copy_if-重载(只需要InputIterators):

template< class InputIt, class Size, class OutputIt>
OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result)
{
    return std::copy_if(first, last, result,
        [&](typename std::iterator_traits<InputIt>::reference)
        {return count && count--;});
}

BTW:它在C++14中变得更好,不需要变量或如此复杂的参数:

std::copy_if(first, last, result,
    [count = some_complicated_expression](auto&&) mutable
    {return count && count--;});

从C++20开始,std::ranges::views::take(e, f)很好地解决了这个问题。。。它终止于输入范围e的末尾,或者当f元素被迭代时,以先到的为准。

您可以将copy_if与自定义谓词一起使用,它适用于较旧版本的c++。

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>

struct LimitTo
{
    LimitTo( const int n_ ) : n(n_)
    {}
    template< typename T >
    bool operator()( const T& )
    {
        return n-->0;
    }
    int n;
};
int main()
{
    std::vector< int > v1{ 1,2,3,4,5,6,7,8 };
    std::vector< int > v2;
    std::copy_if( std::begin(v1), std::end(v1), std::back_inserter(v2), LimitTo(3) );
    std::copy( std::begin(v1), std::end(v1), std::ostream_iterator<int>(std::cout,", ") );
    std::cout << std::endl;
    std::copy( std::begin(v2), std::end(v2), std::ostream_iterator<int>(std::cout,", ") );
    std::cout << std::endl;
}

本例使用谓词LimitTo复制n个元素。

相关内容

  • 没有找到相关文章

最新更新