Edw*_*ard 17 c++ templates c++11 c++-concepts
在回答关于CodeReview的这个问题时,我在思考如何编写模板函数来指示const包含对象的内容.
具体而言,请考虑这个模板化函数
#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';
}
Run Code Online (Sandbox Code Playgroud)
它需要一个迭代器并根据包含的数字计算平均值,但保证不通过传递的迭代器修改向量.如何将此传达给模板的用户?
请注意,声明如下:
template <class It>
typename std::iterator_traits<It>::value_type average(const It begin,
const It end)
Run Code Online (Sandbox Code Playgroud)
不起作用,因为它不是迭代器,而是迭代器指向的东西,那就是const.我是否必须等待概念标准化?
请注意,我不想要求 const迭代器,而是指示它们可以在这里安全使用.也就是说,我想传达一个我的代码所做的承诺,而不是限制调用者:"我不会修改您的基础数据."
Ton*_*roy 10
template <class ConstIt>
Run Code Online (Sandbox Code Playgroud)
就这么简单.这里没有什么可以在调用方面强制执行,因为非const迭代器也可用于const访问,因此它只是API文档,这就是您选择的参数标识符--API文档.
这确实导致了被调用者/函数端的执行问题 - 所以它不能假装它只会使用迭代器进行const访问然后修改元素.如果你关心它,你可以使用一些标识符来接受参数,明确它不是要在整个函数中随处使用,然后创建一个const_iterator带有更方便标识符的版本.这可能很棘手,因为通常你不知道迭代器类型是否是容器的成员,更不用说容器类型是什么以及它是否也有const_iterator,所以某些概念确实是理想的 - 手指交叉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_;
};
Run Code Online (Sandbox Code Playgroud)
样品用法:
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';
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1515 次 |
| 最近记录: |