[iterator] function_output_iterator constructed from a lambda function is not assignable
Consider the following code snippet:
auto f = [](int x) { std::cout << x; };auto it =
boost::make_function_output_iterator(f);decltype(it) it2 = it; // Ok,
copied
it2 = it; // Does not compile, cannot assign!
The problem is, function_output_iterator constructed in this way is not
assignable, and thus does not satisfy the Iterator
http://en.cppreference.com/w/cpp/concept/Iterator concept, which requires
type to be CopyAssignable
http://en.cppreference.com/w/cpp/concept/CopyAssignable.
This is not a bug, since boost Function Output Iterator documentation
http://www.boost.org/doc/libs/1_60_0/libs/iterator/doc/function_output_itera...
clearly says
http://www.boost.org/doc/libs/1_60_0/libs/iterator/doc/function_output_itera...
:
UnaryFunction must be Assignable and Copy Constructible.
While assignment operator of a lambda function
http://en.cppreference.com/w/cpp/language/lambda is deleted:
ClosureType& operator=(const ClosureType&) = delete;
So this behaviour is technically correct, but for me is somewhat
unexpected. I think it is a perfectly reasonable desire to construct
function_output_iterator given a closure produced by lambda function. It
seems inconvenient to me why this use case causes a problem.
Can you suggest a workaround for this situation? Or maybe a way of
improving function_output_iterator to overcome this issue?
Personally, I came up with a trick to fix this in a situation, when I'm
sure iterator and its copies won't outlive the closure object. In this case
we may wrap closure with std::ref:
auto it = boost::make_function_output_iterator(std::ref(f));
This works quite fine, but obviously is not always possible.
Another options is to store closure in std::function:
std::function
Mikhail Matrosov wrote:
Can you suggest a workaround for this situation? Or maybe a way of improving function_output_iterator to overcome this issue?
One way of working around this limitation would be to define a class optional_fn<F> that is like optional<F> but doesn't use F::operator= in its assignment, always destroying the left side and copying instead. Its operator() would forward to F::operator(). So you'd be able to construct a function_output_iterator from make_optional_fn( []... ). This would also make the iterator default constructible although this is not necessary for output iterators. It is necessary for make_transform_iterator though, which would also benefit from a similar treatment. This should arguably be built into the iterators themselves; I think that this has come up before on the list, but I don't remember the outcome of the discussion.
This should arguably be built into the iterators themselves; I think that this has come up before on the list, but I don't remember the outcome of the discussion.
The problem is that there is overhead from using `boost::optional` in all iterators. A better approach is to create fat ranges rather than fat iterators. So instead the function object is stored in the range, and the iterators reference the function from the range. Fat ranges also fixes the problem with dealing with temporary ranges as well. This is the approach that Eric Niebler uses for his ranges-v3, and the reason why he started writing the library: http://ericniebler.com/2013/11/07/input-iterators-vs-input-ranges/ Paul
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Paul Fultz II wrote:
The problem is that there is overhead from using `boost::optional` in all iterators.
What overhead is there? A single bool? This doesn't seem that terrible to me.
On Sunday, February 14, 2016 at 9:20:34 PM UTC-6, Peter Dimov wrote:
Paul Fultz II wrote:
The problem is that there is overhead from using `boost::optional` in all iterators.
What overhead is there? A single bool? This doesn't seem that terrible to me.
I agree, but from what I remember from the discussion others seem to think it was pretty terrible.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On Sunday, February 14, 2016 at 6:28:47 PM UTC-6, Mikhail Matrosov wrote:
Consider the following code snippet:
auto f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it; // Ok, copied it2 = it; // Does not compile, cannot assign!
The problem is, function_output_iterator constructed in this way is not assignable, and thus does not satisfy the Iterator http://en.cppreference.com/w/cpp/concept/Iterator concept, which requires type to be CopyAssignable http://en.cppreference.com/w/cpp/concept/CopyAssignable.
One way to deal with this is to put it into boost::optional. However, it now
needs to be dereferenced. This can be easily done with `fit::indirect`:
template<class F>
fit::indirect_adaptor
On Sunday, February 14, 2016 at 9:18:15 PM UTC-6, Peter Dimov wrote:
Paul Fultz II wrote:
One way to deal with this is to put it into boost::optional.
boost::optional<T> uses T::operator= when the source and the target hold a value.
It seems that boost::optional is not constrained properly, the following
compiles just fine:
struct not_assignable
{
not_assignable& operator=(const not_assignable&)=delete;
};
static_assert(!std::is_copy_assignable
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 2016-02-14 22:42, Mikhail Matrosov wrote:
Consider the following code snippet:
auto f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it; // Ok, copied it2 = it; // Does not compile, cannot assign!
Since the lambda does not capture anything, you might try to convert it to a function pointer, which would make it assignable. typedef void (*lambda_t)(int); auto it = make_function_output_iterator((lambda_t)f); If you do have to capture variables, you might want to use std::bind to store the captures and a pointer to the lambda function without captures. Or just use std::bind with a normal function.
On Monday, February 15, 2016 at 2:36:02 PM UTC-6, Andrey Semashev wrote:
On 2016-02-14 22:42, Mikhail Matrosov wrote:
Consider the following code snippet:
auto f = ;auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it; // Ok, copied it2 = it; // Does not compile, cannot assign!
Since the lambda does not capture anything, you might try to convert it to a function pointer, which would make it assignable.
typedef void (*lambda_t)(int); auto it = make_function_output_iterator((lambda_t)f);
If you do have to capture variables, you might want to use std::bind to store the captures and a pointer to the lambda function without captures. Or just use std::bind with a normal function.
That is another way. Its simpler just to append a `+` to do that though: auto it = make_function_output_iterator(+[](int x) { std::cout << x; }); Paul
Hi,
2016-02-15 4:42 GMT+09:00 Mikhail Matrosov
Consider the following code snippet:
auto f = [](int x) { std::cout << x; };auto it = boost::make_function_output_iterator(f);decltype(it) it2 = it; // Ok, copied it2 = it; // Does not compile, cannot assign!
FYI, My library has `regular` function. The function convert function object to `DefaultConstructible` & `Assignable`. Documentation: http://htmlpreview.github.io/?https://github.com/faithandbrave/OvenToBoost/b... Implementation: https://github.com/Flast/OvenToBoost/blob/master/include/boost/range/regular... https://github.com/Flast/OvenToBoost/blob/master/include/boost/range/detail/... https://github.com/Flast/OvenToBoost/blob/master/include/boost/range/detail/... https://github.com/Flast/OvenToBoost/blob/master/include/boost/range/detail/... The Boost Range Extension library is now waiting review. http://www.boost.org/community/review_schedule.html And FYI, related pull request: https://github.com/boostorg/iterator/pull/20 Thanks, Akira
======================== Akira Takahashi http://faithandbrave.github.io/
participants (5)
-
Akira Takahashi
-
Andrey Semashev
-
Mikhail Matrosov
-
Paul Fultz II
-
Peter Dimov