Opened 13 years ago

Last modified 13 years ago

#3446 new Feature Requests

[boost] [fusion] transform does not return a mutable view

Reported by: jhellrung@… Owned by: Joel de Guzman
Milestone: Boost 1.41.0 Component: fusion
Version: Boost 1.40.0 Severity: Optimization
Keywords: Cc: Christopher Schmidt

Description

Based on the documentation (and my own experience), it doesn't appear that transform will return a mutable transform_view, since transform receives its sequence argument always by const reference. Is this intentional, or an oversight? It seems like there's no loss in providing 2 overloads of transform, one accepting a const reference and one accepting a non-const reference.

Change History (14)

comment:1 by Joel de Guzman, 13 years ago

That is by design. A transform_view is lazily evaluated. You'd want to assign back to the original container if you want it mutated. The effect and performance is the same.

Do you have some code? I can probably recommend a way to do what you want.

comment:2 by Jeffrey Hellrung <jhellrung@…>, 13 years ago

I was trying to do something along the lines of

copy(source, transform(dest, project())

where source and dest are Boost.Fusion conforming sequences (but not necessarily the data structures from the Boost.Fusion library); copy is a function I wrote that operates on Boost.Fusion sequences (with the expected semantics; I couldn't find something in Boost.Fusion that would accomplish the same thing); and project is a function object returning a reference to a particular member variable of each element of dest.

What do you think?

Thanks,

  • Jeff

comment:3 by Joel de Guzman, 13 years ago

copy is just assign:

dest = src

It works with any src and dest type as long as src is a fusion sequence and dest is a fusion container with the same element types and same number of elements.

a mutating transform is just:

for_each(s, f)

So, I dont see why your code can't be rewritten as:

dest = src; for_each(dest, project());

What am I missing?

comment:4 by Jeffrey Hellrung <jhellrung@…>, 13 years ago

First, I wasn't aware that assignment of a Boost.Fusion sequence to, e.g., a boost::array would work? I admit I've never tried it...

Second, think of project as something like

project
{
    template< class First, class Second >
    First& operator()(std::pair< First, Second >& x) const
    { return x.first; }
}

I essentially want something to the effect of

for i = 0, ..., size
    dest[i].member_var = source[i]
  • Jeff

comment:5 by Joel de Guzman, 13 years ago

First, I wasn't aware that assignment of a Boost.Fusion sequence to, e.g., a boost::array would work? I admit I've never tried it...

Ah indeed it won't. boost::array is not a fusion container. So you have a good use case for copy indeed. I suggest you polish it, provide docs, and I'd gladly add that to the library.

Now, back to what you want. It seems that you don't need in-place mutation at all!

copy(transform(src, project()), dest);

where project returns src[i].member_var for each member. This is as fast as you expect it to be since transform is lazily evaluated.

Thoughts?

comment:6 by Jeffrey Hellrung <jhellrung@…>, 13 years ago

Re copy: Sounds good, although I'd have to familiarize myself with the boost quickbook (?) documentation creator thingy. Any helpful suggestions?

The problem your suggestion is it's backwards from what I want:

copy(transform(src, project()), dest) <=> dest[i] = src[i].member_var

whereas I'm aiming toward

copy(src, transform(dest, project())) <=> dest[i].member_var = src[i]

  • Jeff

comment:7 by Joel de Guzman, 13 years ago

Ok, I'm convinced. You have a valid use case. Care to submit a patch + docs? I'd also want to have your copy algo in. As for qbk, just copy one of the qbk files and tweak. That's the easiest path. I'll do the rest.

comment:8 by Joel de Guzman, 13 years ago

Oh, please add tests too, if you will.

THANKS!

comment:9 by Jeffrey Hellrung <jhellrung@…>, 13 years ago

Okay, I'll try my hand at it. Could be a week or two, though ;)

Also, there's another Fusion addition I use that I've found useful: as_mpl_vector. It is strictly a metafunction which converts a Boost.Fusion conforming sequence into a Boost.MPL vector. I know all "built-in" Fusion sequences are already MPL sequences (with the appropriate include), but it didn't seem like adapted Fusion sequences also had this property, hence the need arose. I've occasionally needed this to add compile-time checks or type-computations on a Boost.Fusion parameter to a function. Let me know if this also sounds like something that could be added, or if you need an example use case.

  • Jeff

comment:10 by Joel de Guzman, 13 years ago

Sounds good, but why stop at vector? It would make sense to have all: vector/list/map/set. ;-)

comment:11 by Christopher Schmidt, 13 years ago

I implemented that very feature in my c++0x port of fusion. Feel free to copy&paste the relevant changes. You can find the code in the sandbox (/sandbox/SOC/2009/fusion)

What particular property/feature are you missing when working with MPL-fied fusion sequences?

comment:12 by Christopher Schmidt, 13 years ago

Cc: Christopher Schmidt added

comment:13 by Jeffrey Hellrung <jhellrung@…>, 13 years ago

I'm not sure I understand your question, but here's an attempt at an answer ;)

If you have a function, e.g., that takes any Boost.Fusion conforming sequence as a parameter, and whose return type or intermediate types must be deduced from the types in the sequence, it is often convenient to use the Boost.MPL metafunctions on this type sequence. However, although all the containers in the Boost.Fusion library are (conveniently, via an include) conforming MPL sequences, a Boost.Fusion conforming sequence is not generally required to be a Boost.MPL conforming sequence (think boost::array), so the use of Boost.MPL metafunctions on the type sequence generally requires a conversion to a Boost.MPL vector (or other Boost.MPL sequence).

Thanks for the code reference. I still need to find some downtime to add these proposals to the current Boost.Fusion version :/

in reply to:  13 comment:14 by Christopher Schmidt, 13 years ago

Replying to Jeffrey Hellrung <jhellrung@…>: I got it. Sorry, I just came back from work when I wrote the question above - it would have been clear in the first place if I'd mulled it over once more.

Note: See TracTickets for help on using tickets.