在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。与此同时:
  • 让您的 call 者告诉您容器类型
  • 编写自己的特征,或者
  • 写一个简单的包装类,其中包含一个迭代器,并确保只有对引用数据的const访问才能退出
  • 接口(interface)

    最后一个包装器方法如下所示(并非所有迭代器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/

    10-11 22:50
    查看更多