2016-12-27 59 views
0

主要是作为一个练习我实现从基地B转换立足10如何减少迭代器的样板?

unsigned fromBaseB(std::vector<unsigned> x,unsigned b){ 
    unsigned out = 0; 
    unsigned pow = 1; 
    for (size_t i=0;i<x.size();i++){ 
     out += pow * x[i]; 
     pow *= b; 
    } 
    return out; 
} 

int main() { 
    auto z = std::vector<unsigned>(9,0); 
    z[3] = 1; 
    std::cout << fromBaseB(z,3) << std::endl; 
} 

现在我想写这使用的算法。例如。使用accumulate我可以写

unsigned fromBaseB2(std::vector<unsigned> x,unsigned b){ 
    unsigned pow = 1; 
    return std::accumulate(x.begin(), 
          x.end(),0u, 
          [pow,b](unsigned sum,unsigned v) mutable { 
           unsigned out = pow*v; 
           pow *= b; 
           return out+sum; 
          }); 
} 

但是,我认为这不是更好的代码。事实上,将它作为内部产品写入会更自然,因为这正是我们必须计算的基础变革。但使用inner_product我需要一个迭代器:

template <typename T> struct pow_iterator{ 
    typedef T value_type; 
    pow_iterator(T base) : base(base),value(1) {} 
    T base,value; 
    pow_iterator& operator++(){ value *= base;return *this; } 
    T operator*() {return value; } 
    bool operator==(const pow_iterator& other) const { return value == other.value;} 
}; 

unsigned fromBaseB3(std::vector<unsigned> x,unsigned b){ 
    return std::inner_product(x.begin(),x.end(),pow_iterator<unsigned>(b),0u); 
} 

使用迭代器,现在称该算法是不错的干净,但我不得不写大量的样板代码的迭代器。也许这只是我对算法和迭代器应该如何使用的误解......实际上,这只是我常常遇到的一个普遍问题的一个例子:我有一系列基于简单模式计算的数字,而我想要有一个迭代器,当解除引用时返回该序列中相应的数字。当序列存储在一个容器中时,我只需使用容器提供的迭代器,但我也希望这样做,当没有容器存储值时也是如此。我当然可以尝试编写自己的通用迭代器来完成这项工作,但是标准库中是否存在可以帮助您的工作?

对我来说,感觉有点怪怪的,我可以使用lambda欺骗accumulate成计算内积,而是利用inner_product直接我必须做些额外的事情(无论是预先计算的权力,并将它们存储在一个容器中,或者写一个迭代器,即单独的class)。

tl; dr:是否有简单的方法来减少上述pow_iterator的样板?

更一般的问题(但可能太宽泛)问题:对于未存储在容器中的值序列使用迭代器是否“正常”,但仅在迭代器被解除引用时才计算?有没有实现它的“C++方法”?

+0

看看boost.iterator库。特别是iterator_adapter和iterator_facade。 –

回答

1

正如Richard Hodges在评论中写道的,你可以看看boost::iterator。或者,有range-v3。如果你顺其自然,还有几种可行的方法。下面显示了如何boost::iterator::counting_iteratorboost::iterator::transform_iterator(C++ 11),这样做的:

#include <iostream> 
#include <cmath> 

#include <boost/iterator/counting_iterator.hpp> 
#include <boost/iterator/transform_iterator.hpp>                       

int main() { 
    const std::size_t base = 2; 
    auto make_it = [](std::size_t i) { 
     return boost::make_transform_iterator(
      boost::make_counting_iterator(i), 
      [](std::size_t j){return std::pow(base, j);});}; 
    for(auto b = make_it(0); b != make_it(10); ++b) 
     std::cout << *b << std::endl; 
} 

下面是输出:

$ ./a.out 
1 
2 
4 
8 
16 
32 
64 
128 
256 
512