2016-12-27 40 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