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)

transform_iterator.patch (1009 bytes ) - added by Daniel Walker 12 years ago.
use boost::optional to store function objects
transform_iterator.2.patch (1.5 KB ) - added by Daniel Walker 12 years ago.
use boost::optional to store function objects with non-trivial constructors as suggested by Jeffrey Lee Hellrung

Download all attachments as: .zip

Change History (9)

by Daniel Walker, 12 years ago

Attachment: transform_iterator.patch added

use boost::optional to store function objects

by Daniel Walker, 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 sdebionne, 11 years ago

This patch solves the problem mentionned here :

http://boost.2283326.n4.nabble.com/Bind-Interoperability-of-bind-mem-fn-with-transform-iterator-td2668312.html

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 Dave Abrahams, 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 Dave Abrahams, 10 years ago

Owner: changed from Dave Abrahams to jeffrey.hellrung

comment:4 by Taras Kozlov, 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 doesnt 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 olivier-m.pena@…, 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 Dave Abrahams, 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 olivier-m.pena@…, 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 ?

Note: See TracTickets for help on using tickets.