Generating functors with iterator behavior

前端 未结 4 1739
温柔的废话
温柔的废话 2021-02-04 13:53

I have a question, which very likely has been asked like this before, because I think what I want is something that a considerable amount of people would want. However I could n

4条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-04 14:14

    I wonder if this could be called tabulation. If so, what do you thing about the following interface?

    #include 
    #include 
    #include 
    
    #include "tabulate.hpp"
    
    template
    void show(const T& data) {
      for(const auto & x: data) std::cout << x << " ";
      std::cout << std::endl;
    }
    
    int main() {
      auto fun = [](double x) { return 2.0 * x; };
    
      std::vector x  {1, 2, 3, 4, 5};
    
      std::cout << "using range-for" << std::endl;
      for(const auto & fx : tabulate(fun, x.begin(), x.end())) {
        std::cout << fx << std::endl;
      }
    
      std::cout << "initializing a vector" << std::endl;
      auto init = tabulate(fun, x.begin(), x.end());
      std::vector values(init.begin(), init.end());
      show(values);
    
      std::cout << "automatic construction of vector" << std::endl;
      auto in_vector = make_tabulation>(fun, x);
      show(in_vector);
    
      std::cout << "automatic construction of list" << std::endl;
      auto in_list   = make_tabulation>(fun, x);
      show(in_list);
    }
    

    Which is implemented by the following header:

    #pragma once
    #include 
    
    template::value_type
             >
    class tabulate_iterator
    
        : public std::iterator {
    
     public:
    
      tabulate_iterator()
          : m_is_valid(false) { }
    
      tabulate_iterator(Fun& fun, InputIt beg, InputIt end)
          : m_fun(&fun),
            m_beg(beg),
            m_end(end),
            m_is_valid(beg != end) {
        this->read();
      }
    
      const T& operator*() const {
        return m_current;
      }
    
      const T* operator->() const {
        return &(operator*());
      }
    
      tabulate_iterator& operator++() {
        this->read();
        return *this;
      }
    
      tabulate_iterator operator++(int) {
        auto tmp = *this;
        this->read();
        return tmp;
      }
    
      bool equals(const tabulate_iterator& other) const {
        return ((m_is_valid == other.m_is_valid) and
                (not m_is_valid));
      }
    
      bool operator==(const tabulate_iterator& other) const {
        return this->equals(other);
      }
    
      bool operator!=(const tabulate_iterator& other) const {
        return not this->equals(other);
      }
    
     private:
    
      void read() {
        if(m_is_valid and m_beg != m_end) {
          m_current = (*m_fun)(*m_beg++);
        } else {
          m_is_valid = false;
        }
      }
    
      T       m_current;
      Fun*    m_fun;
      InputIt m_beg;
      InputIt m_end;
      bool    m_is_valid;
    
    };
    
    template::value_type
             >
    class tabulate_range {
    
     public:
    
      tabulate_iterator begin() const {
        return m_it;
      }
    
      tabulate_iterator end() const {
        return m_it_end;
      }
    
     private:
    
      template
      friend tabulate_range tabulate(Fun_, InputIt_, InputIt_);
    
      tabulate_range(Fun fun, InputIt beg, InputIt end)
          : m_it(fun, beg, end),
            m_it_end() { }
    
      tabulate_iterator m_it;
      tabulate_iterator m_it_end;
    };
    
    template::value_type
             >
    tabulate_range tabulate(Fun fun, InputIt beg, InputIt end) {
      return tabulate_range(fun, beg, end);
    }
    
    template
    OutContainer make_tabulation(Fun fun, const InContainer& x) {
      auto init = tabulate(fun, x.begin(), x.end());
      return OutContainer(init.begin(), init.end());
    }
    

    Some caveats: I just cracked this code in the spur of the moment, so bugs are likely; take this as a proof of concept.

    Compilation (GCC 4.8.2/Linux; ICC 14.0.2 20140120/Linux):

    {CXX} tabulate.cpp -std=c++11 -Wall -Wextra -Werror
    

    Output:

    $ ./a.out
    using range-for
    2
    4
    6
    8
    10
    initializing a vector
    2 4 6 8 10
    automatic construction of vector
    2 4 6 8 10
    automatic construction of list
    2 4 6 8 10
    

提交回复
热议问题