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
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