如果我正在编写一个库并且我有一个需要返回一系列值的函数,我可以这样做:
std::vector<int> get_sequence();
但是,这要求库用户使用 std::vector<> 容器,而不是允许他们使用他们想使用的任何容器。此外,它可以添加返回数组的额外拷贝(取决于编译器是否可以对其进行优化),这可能会对性能产生负面影响。
理论上,您可以通过制作一个采用开始和结束迭代器的模板函数来启用任意容器的使用(并避免不必要的额外复制):
template<class T_iter> void get_sequence(T_iter begin, T_iter end);
然后该函数会将序列值存储在迭代器给定的范围内。但这样做的问题是,它需要您知道序列的大小,以便您在 begin
和 end
之间有足够的元素来存储序列中的所有值。
我想到了一个接口(interface),例如:
template<T_insertIter> get_sequence(T_insertIter inserter);
这要求 T_insertIter 是一个插入迭代器(例如,使用 std::back_inserter(my_vector)
创建),但这似乎很容易被误用,因为编译器很乐意接受非插入迭代器,但在运行时会出现错误。
那么,是否有设计返回任意长度序列的通用接口(interface)的最佳实践?
最佳答案
让 get_sequence 返回一个(自定义)forward_iterator
类,该类按需生成序列。 (它也可以是更高级的迭代器类型,如 bidirectional_iterator
如果这对您的序列实用。)
然后用户可以将序列复制到他们想要的任何容器类型中。或者,它们可以直接在您的迭代器上循环并完全跳过容器。
您将需要某种结束迭代器。在不知道您是如何生成序列的情况下,很难准确地说出您应该如何实现它。一种方法是让你的迭代器类有一个返回结束迭代器的静态成员函数,比如:
static const my_itr& end() { static const my_itr e(...); return e; };
其中 ...
表示创建结束迭代器(可能使用私有(private)构造函数)所需的任何参数。然后你的循环看起来像:
for (my_itr i = get_sequence(); i != my_itr::end(); ++i) { ... }
这是一个生成连续整数序列的前向迭代器类的简单示例。显然,这可以很容易地变成一个双向或随机访问迭代器,但我想让这个例子保持小。
#include <iterator>
class integer_sequence_itr
: public std::iterator<std::forward_iterator_tag, int>
{
private:
int i;
public:
explicit integer_sequence_itr(int start) : i(start) {};
const int& operator*() const { return i; };
const int* operator->() const { return &i; };
integer_sequence_itr& operator++() { ++i; return *this; };
integer_sequence_itr operator++(int)
{ integer_sequence_itr copy(*this); ++i; return copy; };
inline bool operator==(const integer_sequence_itr& rhs) const
{ return i == rhs.i; };
inline bool operator!=(const integer_sequence_itr& rhs) const
{ return i != rhs.i; };
}; // end integer_sequence_itr
//Example: Print the integers from 1 to 10.
#include <iostream>
int main()
{
const integer_sequence_itr stop(11);
for (integer_sequence_itr i(1); i != stop; ++i)
std::cout << *i << std::endl;
return 0;
} // end main
关于用于以通用方式返回序列的 C++ API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/97447/