Using Boost Adaptors with C++11 Lambdas

Using Boost adaptors with C++11 lambdas

http://smellegantcode.wordpress.com/2011/10/31/linq-to-c-or-something-much-better/

But you can use this, that works well.

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>
#include <functional>

int main() {
std::vector<int> v{
1,5,4,2,8,5,3,7,9
};
std::function<int(int)> func = [](int i) { return -i; };
std::cout << *boost::min_element(v | boost::adaptors::transformed(
func)) << std::endl;
return 0;
}

http://liveworkspace.org/code/b78b3f7d05049515ac207e0c12054c70

#define BOOST_RESULT_OF_USE_DECLTYPE works fine in VS2012 for example.

boost transform iterator and c++11 lambda

Well lambdas don't play nice, since they are not default constructible, which is necessary for iterators. Here is a wrapper I use for lambdas:

#define RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); }

template<class Fun>
struct function_object
{
boost::optional<Fun> f;

function_object()
{}
function_object(Fun f): f(f)
{}

function_object(const function_object & rhs) : f(rhs.f)
{}

// Assignment operator is just a copy construction, which does not provide
// the strong exception guarantee.
function_object& operator=(const function_object& rhs)
{
if (this != &rhs)
{
this->~function_object();
new (this) function_object(rhs);
}
return *this;
}

template<class F>
struct result
{};

template<class F, class T>
struct result<F(T)>
{
typedef decltype(std::declval<Fun>()(std::declval<T>())) type;
};

template<class T>
auto operator()(T && x) const RETURNS((*f)(std::forward<T>(x)))

template<class T>
auto operator()(T && x) RETURNS((*f)(std::forward<T>(x)))
};

template<class F>
function_object<F> make_function_object(F f)
{
return function_object<F>(f);
}

Then you can just do this:

int main()
{
vector<int> a = {0,3,1,};
vector<int> b = {100,200,300,400};

cout<<*br::max_element(a|badpt::transformed(make_function_object([&b](int r)->int{return b[r];};)))<<endl;
}

How do I use boost::transformed to modify a sequence using a lambda in a template construct?

The error:

test.cpp:29:20: error: no match for ‘operator|’ (operand types are ‘const std::vector’ and ‘std::function >(int)>’)
return outputs | fun;

should be perfectly clear. There is no operator| for operands vector and a function. Your second operand should be a boost adaptor which actually defines the operator. Probably like this:

return outputs | boost::adaptors::transformed(fun);

Also in this code:

std::function<MyStruct<Sequence>(int)> fun =
[](const typename Sequence::value_type output)
{
return MyStruct<typename Sequence::value_type>(output, SomeFun(output));
};

According to the type declaration, fun should return a MyStruct<Sequence> but your lambda returns a MyStruct<typename Sequence::value_type>. Also, you probably shouldn't hardcode the parameter type as int if the lambda expects a Sequence::value_type. You should probably declare fun as type Converter<Sequence>. Also, fix the parameter type of the lambda and the function to match with Converter (pay attention to the reference).

Using Boost adaptors with std::bind expressions

Here's the problem:

  1. The standard doesn't require std::bind's return value to be copy assignable; only move constructible (and copy constructible if all bound objects are also copy constructible). For lambdas, their copy assignment operators are required to be deleted.

  2. The range adaptor actually uses transform_iterator, so the function object gets stored in the iterator.

  3. Iterators must be copy assignable, min_element tries to do that, and your program blows up.

With the proliferation of lambdas in C++11, I'd call this a problem with the boost library, which was not designed with copy-constructible-but-not-copy-assignable function objects in mind.

I'd actually suggest wrapping the resulting function object in a reference_wrapper:

int min = *boost::min_element(values | boost::adaptors::transformed(std::ref(fun)));

This also saves the cost of making extra copies of the functor whenever the iterator is copied.

In the two options you listed, boost::bind should be more efficient because it doesn't have to do type erasure.

Using C++11 lambda with boost::multi_index

Lambdas may not be used in unevaluated contexts1. I'm not sure if this qualifies as an unevaluated context, but the approach involving decltype( [](int){} ) would2.

Stateless Lambdas do not appear to have a constexpr conversion-to-function-pointer (this is probably an oversight), otherwise this would work:

template<class T>using type=T;
template< void(*)(int) > struct test {};

constexpr type<void(int)>* f = [](int){};

int main() {
test<f> x;
}

and it might even work if you passed the lambda directly to a void(*)(int) function-pointer parameter.

This leaves you with writing your lambda as an old-school function.


1 This is probably to make compiler's lives easier (as far as I can tell, the type of a lambda in a header file need not be consistent between compilation units under the current standard? But I'm not certain about that.)

2 This prevents you from passing it as a pure type and then invoking it. Lambdas also lack constructors. A hack whereby you construct a stateless lambda (or a reference to same) then invoke it would work in every implementation, unless the compiler noticed your slight of hand, but it is undefined behavior.

This leads to this hack:

#include <iostream>

auto f() { return [](){std::cout <<"hello world.\n";}; }

template<class Lambda>
struct test {
void operator()() const {
(*(Lambda*)nullptr)();
}
};

int main() {
test<decltype(f())> foo;
foo();
}

which is both useless and undefined behavior, but does invoke a lambda we passed as a template parameter to test technically. (C++14)

Boost-range not working with C++1y init-capture mutable lambda

It's just that closure-types don't have nested typedefs that boost::mpl apparently requires. It works if you convert the lambda expression to std::function:

#include <iostream>
#include <iterator>
#include <vector>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>

template<class R>
auto delta_beg(R const& rng1, R const& rng2)
{
using Elem = typename R::value_type;
std::function<Elem(Elem const&)> f =
[first2 = begin(rng2)](Elem const& e) { return e - *first2; };
return rng1 | boost::adaptors::transformed(f);
}

template<class R>
auto delta_rng(R const& rng1, R const& rng2)
{
using Elem = typename R::value_type;
std::function<Elem(Elem const&)> f =
[first2 = begin(rng2)](Elem const& e) mutable { return e - *first2++; };
return rng1 | boost::adaptors::transformed(f);
}

int main()
{
auto r1 = std::vector<int>{ 8, 10, 12, 15 };
auto r2 = std::vector<int>{ 1, 2, 9, 13 };

// prints 7, 9, 11, 14
boost::copy(delta_beg(r1, r2), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n";

// ERROR, should print 7, 8, 3, 2
boost::copy(delta_rng(r1, r2), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n";
}

Live demo.

How to encapsulate custom iterator in function using boost-range

In:

auto myFilter = [](const std::vector<int>& v, int r) {
return v | boost::adaptors::filtered([&r](auto v) { return v%r == 0; });
};

It returns another range adaptor while r captured by reference becomes a dangling reference. To fix it capture r by value:

auto myFilter = [](const std::vector<int>& v, int r) {
return v | boost::adaptors::filtered([r](auto v) { return v%r == 0; });
}; ^
+--- capture by value

How do I use boost::adaptors::transformed to produce a range from a templated class and a vector?

The error tells you boost::result_of<const Converter<int>(int&)> doesn't have the type member. In other words, the function call operator doesn't work when a const Converter<int> object is used. Once you know the problem, it's easy to see what's wrong:

return_type operator()(const T& value) const
// ^^^^^
{
return return_type(value);
}

How do I use boost.lambda with boost.range to select from a container?

operator. is not overloadable, thus it can never do anything sensible on a placeholder.


Boost.Lambda (and Boost.Phoenix v1 and v2, which were based on Boost.Lambda) implements its own result_of protocol rather than the TR1 result_of protocol, so Boost.Lambda functors will not work with anything using boost::result_of or std::tr1::result_of (as Boost.Range does).

That said, Boost.Phoenix v3, slated to be released in Boost 1.47, is the official replacement for Boost.Lambda and does implement the TR1 result_of protocol, and so does play nice with boost::result_of (and consequently Boost.Range).

Your options are to either use Boost.Bind instead of Boost.Lambda, in which case the following is valid:

transformed(bind(&myObjectType::myMember, _1))

or you can use Boost.Phoenix v3 instead of Boost.Lambda (either get Boost.Phoenix out of trunk now or wait for Boost 1.47), in which case the Boost.Bind syntax is valid, as well as the following alternative:

transformed(_1->*&myObjectType::myMember)


Related Topics



Leave a reply



Submit