jon*_*ner 4 c++ generics api sequences
如果我正在编写一个库,并且我有一个需要返回一系列值的函数,我可以这样做:
std::vector<int> get_sequence();
Run Code Online (Sandbox Code Playgroud)
但是,这需要库用户使用std :: vector <>容器,而不是允许它们使用他们想要使用的任何容器.此外,它还可以添加返回数组的额外副本(取决于编译器是否可以优化),这可能会对性能产生负面影响.
理论上,您可以通过创建一个带有开始和结束的模板化函数来启用任意容器(并避免不必要的额外复制):
template<class T_iter> void get_sequence(T_iter begin, T_iter end);
Run Code Online (Sandbox Code Playgroud)
然后,该函数将序列值存储在迭代器给定的范围内.但问题在于它需要您知道序列的大小,以便在序列之间存储足够的元素begin并end存储所有值.
我想过一个界面如:
template<T_insertIter> get_sequence(T_insertIter inserter);
Run Code Online (Sandbox Code Playgroud)
这要求T_insertIter是一个插入迭代器(例如用它创建std::back_inserter(my_vector)),但这似乎太容易被滥用,因为编译器很乐意接受非插入迭代器,但在运行时会表现不正确.
那么设计返回任意长度序列的通用接口是否有最佳实践?
get_sequence返回一个forward_iterator按需生成序列的(自定义)类.(它也可能是更高级的迭代器类型,bidirectional_iterator如果这对您的序列是实用的.)
然后,用户可以将序列复制到他们想要的任何容器类型中.或者,它们可以直接在您的迭代器上循环并完全跳过容器.
你需要某种结束迭代器.如果不确切知道如何生成序列,很难确切地说明你应该如何实现它.一种方法是让你的迭代器类有一个返回结束迭代器的静态成员函数,如:
static const my_itr& end() { static const my_itr e(...); return e; };
Run Code Online (Sandbox Code Playgroud)
where ...表示创建结束迭代器所需的任何参数(可能使用私有构造函数).然后你的循环看起来像:
for (my_itr i = get_sequence(); i != my_itr::end(); ++i) { ... }
Run Code Online (Sandbox Code Playgroud)
这是一个前向迭代器类的简单示例,它生成一系列连续的整数.显然,这可以很容易地变成双向或随机访问迭代器,但我想保持示例小.
#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
Run Code Online (Sandbox Code Playgroud)
std::list<int>稍微好一点,IMO。请注意,这不需要列表中数据的额外副本,因为它只是复制指针。
这完全取决于你的消费者。我说,如果您期望他们成为 C++ 开发人员,请为他们提供std容器类之一。
我唯一想到的另一件事是你会这样做:
void get_sequence(std::tr1::function<void(int)> f);
Run Code Online (Sandbox Code Playgroud)
然后调用者可以使用std::tr1::bind你的函数调用get_sequence他们想要的(或不)任何对象上的任何函数。您只需不断调用f您正在创建的每个元素即可。
| 归档时间: |
|
| 查看次数: |
822 次 |
| 最近记录: |