为算法指定输入和输出范围

时间:2015-09-29 21:42:34

标签: c++ c++11

标准库中有许多用例,我遇到了自己的代码,在这种情况下,我希望传递输入和输出范围必须相同,通常是某种算法。目前这需要三个,或四个如果你要小心,迭代器。通常会有一堆检查以确保迭代器有意义。

我知道在某些情况下,array_view可能会合并成对/结束迭代器对,但仍然需要检查输入和输出array_views可能是不同的大小。是否有关于类的讨论包含输入和输出范围规范?也许范围提案解决了部分或全部这一点,但我不清楚它是如何做的。

1 个答案:

答案 0 :(得分:0)

我经常有类似的用例。我发现最通用的方法是将引用传递给输出'容器'概念而不是范围或迭代器对。然后算法可以根据需要自由调整大小或扩展容器,缓冲区溢出的可能性消失。

(一个简单的人为设计)例子,如:

template<class InputIter, class OutputContainer>
void encrypt_to(OutputContainer& dest, InputIter first, InputIter last)
{
  dest.resize(last - first);
  // ... todo: replace this with some actual encryption
  std::copy(first, last, dest.begin());
}

对于我想隐藏实现的函数,我有一个表示目标容器的抽象接口。它需要虚拟begin()end()resize()方法。

例如:

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

struct mutable_byte_buffer_concept {
    using iterator=uint8_t*;
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
    virtual void resize(size_t newsize) = 0;

    // note : no virtual destructor - by design.
};

template<class Container>
struct mutable_byte_buffer_model : mutable_byte_buffer_concept
{
    mutable_byte_buffer_model(Container& container)
    : container(container)
    {
    }

    virtual iterator begin()  override
    {
        return reinterpret_cast<iterator>(&container[0]);
    }

    virtual iterator end()  override
    {
        return reinterpret_cast<iterator>(&container[0]) + container.size();
    }

    virtual void resize(size_t newsize)  override
    {
        container.resize(newsize);
    }

    Container& container;
};

template<class Container>
auto make_mutable_buffer(Container& c)
-> mutable_byte_buffer_model<Container>
{
    return { c };
}

// note: accepting an rvalue allows me to use polymorphism at the call site without needing any memory allocation
template<class Iter>
void copy_to(mutable_byte_buffer_concept&& dest, Iter first, Iter last)
{
    dest.resize(last - first);
    std::copy(first, last, dest.begin());
}

using namespace std;

auto main() -> int
{
    auto a = "Hello, World"s;
    string b;
    vector<uint8_t> c;
    string d;
    copy_to(make_mutable_buffer(b), begin(a), end(a));
    copy_to(make_mutable_buffer(c), begin(b), end(b));
    copy_to(make_mutable_buffer(d), begin(c), end(c));
    cout << d << endl;
    return 0;
}