I agree. It was a good proposal, and it will be missed.
#include <string>
#include <utility>
#include <ciso646>
#include <iostream>
#include <tuple>
#include <string_view>
#include <memory>
#include <vector>
#include <algorithm>
#include <numeric>
// the concept of a capacity
struct capacity
{
constexpr capacity(std::size_t x) : value_(x) {}
constexpr operator std::size_t() const { return value_; }
std::size_t value_;
};
// not every container supports reserve() so stub it out in the general case
template<class Container>
void reserve(Container&&, std::size_t)
{}
// implement reserve for any vector
template<class T, class A>
void reserve(std::vector<T, A>& vec, std::size_t x)
{
vec.reserve(x);
}
// wrap any container with a library of operations
template<class Container>
struct ops : Container
{
using container_type = Container;
using value_type = typename container_type::value_type;
ops(capacity cap)
: container_type()
{
reserve(my_container(), cap);
}
ops(Container&& c) : Container(std::move(c)) {}
// return a reference to the underlying container
container_type& my_container() {
return static_cast<container_type&>(*this);
}
template<class F>
ops map(F&& f)
{
auto&& source = my_container();
auto result = ops(capacity(source.size()));
std::transform(source.begin(), source.end(), std::back_inserter(result), f);
return result;
}
template<class F = std::plus<>>
auto fold(value_type init = value_type(0), F&& f = F())
{
auto&& source = my_container();
return std::accumulate(source.begin(), source.end(), init, f);
}
};
// test
int main()
{
auto o = ops(std::vector{1,2,3,4});
auto times_two = [](auto x) { return x * 2; };
auto tot = o.map(times_two).fold();
std::cout << tot << std::endl;
}