在CodeReview上响应this question时,我正在考虑如何编写一个模板函数来指示所包含对象的const
-ness。
具体来说,请考虑此模板化功能
#include <iostream>
#include <numeric>
#include <vector>
template <class It>
typename std::iterator_traits<It>::value_type average(It begin, It end) {
typedef typename std::iterator_traits<It>::value_type real;
real sum = real();
unsigned count = 0;
for ( ; begin != end; ++begin, ++count)
sum += *begin;
return sum/count;
}
int main()
{
std::vector<double> v(1000);
std::iota(v.begin(), v.end(), 42);
double avg = average(v.cbegin(), v.cend());
std::cout << "avg = " << avg << '\n';
}
它需要一个迭代器,并根据所包含的数字计算平均值,但是可以保证不会通过传递的迭代器修改 vector 。如何将其传达给模板用户?
请注意,这样声明:
template <class It>
typename std::iterator_traits<It>::value_type average(const It begin,
const It end)
不起作用,因为它不是迭代器,而是迭代器指向的东西,即
const
。我是否需要等待concepts标准化?请注意,我不想使用const迭代器,而是表示可以在此处安全地使用它们。就是说,我不想限制调用者,而是传达了我的代码正在做出的 promise :“我不会修改您的基础数据。”
最佳答案
template <class ConstIt>
就这么简单。在这里,调用方没有任何强制要求,因为非
const
迭代器也可用于const
访问,因此它只是API文档,这就是您选择的参数标识符-API文档。这确实导致了在被调用者/函数方面强制执行的问题-因此不能假装它只会将迭代器用于
const
访问,然后无论如何都要修改元素。如果您对此感到担心,则可以使用一些标识符来接受参数,以表明并非在整个函数中都使用该参数,然后创建一个带有更方便标识符的const_iterator
版本。这可能很棘手,因为通常您不知道迭代器类型是否是容器的成员,更不用说该容器类型是什么,以及它是否也具有const_iterator
,因此某种方式的Concepts确实很理想-双手合十适用于C++ 14。与此同时:const
访问才能退出最后一个包装器方法如下所示(并非所有迭代器API都已实现,因此可以根据需要充实):
template <typename Iterator>
class const_iterator
{
public:
typedef Iterator iterator_type;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
// note: trying to add const to ...:reference or ..:pointer doesn't work,
// as it's like saying T* const rather than T const* aka const T*.
typedef const typename std::iterator_traits<Iterator>::value_type& reference;
typedef const typename std::iterator_traits<Iterator>::value_type* pointer;
const_iterator(const Iterator& i) : i_(i) { }
reference operator*() const { return *i_; }
pointer operator->() const { return i_; }
bool operator==(const const_iterator& rhs) const { return i_ == rhs.i_; }
bool operator!=(const const_iterator& rhs) const { return i_ != rhs.i_; }
const_iterator& operator++() { ++i_; return *this; }
const_iterator operator++(int) const { Iterator i = i_; ++i_; return i; }
private:
Iterator i_;
};
用法示例:
template <typename Const_Iterator>
void f(const Const_Iterator& b__, const Const_Iterator& e__)
{
const_iterator<Const_Iterator> b{b__}, e{e__}; // make a really-const iterator
// *b = 2; // if uncommented, compile-time error....
for ( ; b != e; ++b)
std::cout << *b << '\n';
}
看到它running at ideone.com here。
关于c++ - 如何编写可以使用const迭代器的C++ 11模板,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24675366/