Как сказал @jalf, карта и фолд уже в стандарте, скрыты за разными именами:
- карта ->
std::transform
, находится в заголовке <algorithm>
- fold ->
std::accumulate
, найдено в заголовке <numeric>
Многие другие функциональные возможности можно найти в Boost.Range , который является довольно классной библиотекой. В частности, адаптеры дают реальное функциональное ощущение, поскольку они создают просмотров в других диапазонах. В C ++ 11 возможные предикаты также легко создаются на лету через лямбды.
Boost.Optional может быть вашим «типом параметра», в зависимости от того, что именно вы имеете в виду.
Неизменяемость в C ++ может быть достигнута простым объявлением вашего объекта const
. Вы можете избежать копирования, используя передачу аргументов по ссылке. По правде говоря, это, конечно, не является реальным эквивалентом истинной функциональной неизменности, поскольку неизменяемые контейнеры на функциональных языках могут быть скопированы по вашему желанию и, как правило, просто разделяют внутреннее представление. В конце концов, копирование при записи - это здорово, если ты никогда не пишешь.
На ваших управляемых указателях я понятия не имею, что вы подразумеваете под ними. В C ++ вам обычно вообще не нужны указатели или динамически размещаемые объекты. Просто создайте их «в стеке»: Foo obj;
.
Если вы имеете в виду совместное владение, то есть std::shared_ptr
. Есть даже хороший адаптер диапазона, если вы храните такой указатель в контейнере:
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm/generate.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <vector>
#include <memory>
#include <algorithm>
#include <iterator>
#include <iostream>
int main(){
std::vector<std::shared_ptr<int>> v(5);
int i = 0;
boost::generate(v, [&i]{ return std::make_shared<int>(i++); });
boost::copy(v | boost::adaptors::indirected,
std::ostream_iterator<int>(std::cout));
}
Ваш конкретный пример
my_list.map(f).filter(p).head_opt.get_or_else("not found")
может быть реализовано следующим образом (обратите внимание, что std::vector
является контейнером по умолчанию в C ++):
// Warning, C++11 only!
// Boost.Range doesn't like lambdas without this:
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <boost/optional.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/generate.hpp> // only needed for filling the vector
#include <boost/range/algorithm/copy.hpp> // only needed for printing
// we need a little helper for the optional stuff
struct head_opt_gen{} head_opt; // just a tag type
template<class Range>
auto operator|(Range const& r, head_opt_gen)
-> boost::optional<decltype(r.front())>
{
if(r.empty())
return boost::none;
return r.front();
}
int main(){
using namespace boost::adaptors;
std::vector<int> v(5);
int i = 0;
boost::generate(v, [&]()->int{ ++i; return i*i; });
// first, without the optional stuff
boost::copy(v | transformed([](int x){ return std::to_string(x); })
| filtered([](std::string const& s){ return s.size() > 1; }),
std::ostream_iterator<std::string>(std::cout, "\n"));
std::cout << "=====================\n";
// now with
std::cout << boost::get_optional_value_or(
v | transformed([](int x){ return std::to_string(x); })
| filtered([](std::string const& s){ return s.size() > 2; }) // note: > 2
| head_opt, "none");
}
Скомпилировано с Clang 3.1 Trunk, это приводит к следующему выводу:
16
25
=====================
none