Opened 12 years ago
Last modified 9 years ago
#4189 new Feature Requests
Add better support for non-default constructible function objects
Reported by: | Daniel Walker | Owned by: | jeffrey.hellrung |
---|---|---|---|
Milestone: | Boost 1.43.0 | Component: | iterator |
Version: | Boost 1.42.0 | Severity: | Problem |
Keywords: | transform_iterator | Cc: |
Description
boost::transform_iterator is required to be default constructible, but not all function objects are. For example, boost::mem_fn_t is not default constructible. To allow transform_iterator to model DefaultConstructible with any function object type, Peter Dimov suggested using boost::optional. Thanks to Samuel Debionne for identifying and reporting the problem.
Attachments (2)
Change History (9)
by , 12 years ago
Attachment: | transform_iterator.patch added |
---|
by , 12 years ago
Attachment: | transform_iterator.2.patch added |
---|
use boost::optional to store function objects with non-trivial constructors as suggested by Jeffrey Lee Hellrung
comment:1 by , 11 years ago
This patch solves the problem mentionned here :
I have been using it for more than a year. Could you considerer merging it to trunk ?
the problem is even more acute with Boost.Range adaptors since something as simple as
using namespace boost::range::adaptors; boost::for_each(my_range | transformed(boost::mem_fn(foo)), bar);
won't compile.
comment:2 by , 11 years ago
I'm concerned about the mandatory overhead implied by the use of boost::optional for transform iterators that may not need it. What about making a function object wrapper that adds default-constructibility?
comment:3 by , 10 years ago
Owner: | changed from | to
---|
comment:4 by , 9 years ago
Ive suffered from the same problem, when I tried to use it with lambdas. If lambda has non-empty capture list, it doesn
t provide constructor with zero arguments.
typedef boost::any_range<int, boost::random_access_traversal_tag, int, ptrdiff_t> int_range; int_range f(const vector<double>& v) { vector<double> vec; string str = "Hello"; return vec | boost::adaptors::transformed([str](double v) -> int { return (int)v; }); }
If boost::optional overhead is inacceptable, we may try to use aligned storage + placement new instead.
I also want to notice simple workaround: assigning lambda to std::function will make it work
std::function<int(double)> lambda = [str](double v) -> int { return (int)v; }; return vec | transformed(lambda);
This is not the perfect solution since it involves runtime overhead especially on large data ranges.
comment:5 by , 9 years ago
Same problem than Taras here : transform_iterator assigned to an any_range with gcc 4.8.1. Even without closure.
If not assigned to an any_range, it's ok.
typedef boost::any_range<int, boost::forward_traversal_tag, int, std::ptrdiff_t> int_range; std::vector<int> v; // Fail. int_range range1 = v | boost::adaptors::transformed( [](const int& i) {return i * 2; }); // Ok. int_range range2 = v | boost::adaptors::transformed( std::function<int(const int&)>( [](const int& i) {return i * 2; }));
I would like to add that clang 3.3 compiles successfully.
comment:6 by , 9 years ago
As far as transform_iterator
is concerned, there's nothing it can do about non-default-constructible function objects in C++03 without also penalizing uses of default-constructible function objects. If there's a C++11 type trait that allows detection of deleted default ctors that would sort of let the iterator library introduce the optional<F>
wrapper itself, but it wouldn't help if the default ctor was private. My suggestion here would be to create a generic forwarding function object wrapper around optional<F>
and use that as the function object for your transform_iterator
.
comment:7 by , 9 years ago
Thank you for the explanations. With C++11, std::function may be that wrapper. But I still can't figure out why clang compiles my example ?
use boost::optional to store function objects