[fusion] fusion sequence of non-copy-constructible types

hello, at the last boostcon i had the chance to be introduced to fusion by dan and joel. i appreciate the idea of fusion a lot and the library amazingly detailed. since we have already had great exposure to the mpl the fusion concepts present ample opportunity for new ideas. still, some little things sometimes make it hard for me to keep rolling with fusion: i need to have a vector/list of non-copy-constructible types. using e.g. a standard fusion::vector that does not seem to be possible since objects are constructed first, then copied. of course, i could provide a public copy-constructor but that would in other places remove the compiler enforced contract that those objects are not copied under any circumstances. i also cannot think of a good reason why it is nesseccary to copy in that case. so is there a way of having a fusion sequence that does work on non-copy-constructible types? thanks for any suggestions, oliver

Oliver Mueller wrote:
hello, at the last boostcon i had the chance to be introduced to fusion by dan and joel. i appreciate the idea of fusion a lot and the library amazingly detailed. since we have already had great exposure to the mpl the fusion concepts present ample opportunity for new ideas. still, some little things sometimes make it hard for me to keep rolling with fusion:
i need to have a vector/list of non-copy-constructible types. using e.g. a standard fusion::vector that does not seem to be possible since objects are constructed first, then copied. of course, i could provide a public copy-constructor but that would in other places remove the compiler enforced contract that those objects are not copied under any circumstances. i also cannot think of a good reason why it is nesseccary to copy in that case. so is there a way of having a fusion sequence that does work on non-copy-constructible types?
Hmm... well... a) How do you put a noncopyable object in a container? b) How do you copy a container with noncopyable elements? Fusion vector is based on stl vector. Even stl vector requires copy constructible types. One possibility is to store your object in a smart pointer or wrap it in a reference wrapper. Then, the smart pointer and reference wrapper can be stored in the fusion container. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

on Mon Jul 07 2008, Joel de Guzman <joel-AT-boost-consulting.com> wrote:
Oliver Mueller wrote:
hello, at the last boostcon i had the chance to be introduced to fusion by dan and joel. i appreciate the idea of fusion a lot and the library amazingly detailed. since we have already had great exposure to the mpl the fusion concepts present ample opportunity for new ideas. still, some little things sometimes make it hard for me to keep rolling with fusion:
i need to have a vector/list of non-copy-constructible types. using e.g. a standard fusion::vector that does not seem to be possible since objects are constructed first, then copied. of course, i could provide a public copy-constructor but that would in other places remove the compiler enforced contract that those objects are not copied under any circumstances. i also cannot think of a good reason why it is nesseccary to copy in that case. so is there a way of having a fusion sequence that does work on non-copy-constructible types?
Hmm... well... a) How do you put a noncopyable object in a container?
Direct in-place construction. I think in C++0x it's called "emplace."
b) How do you copy a container with noncopyable elements?
Ya don't. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

David Abrahams wrote:
on Mon Jul 07 2008, Joel de Guzman <joel-AT-boost-consulting.com> wrote:
a) How do you put a noncopyable object in a container?
Direct in-place construction. I think in C++0x it's called "emplace."
Can you do "emplace" without move-construct? With a non-C++0x compiler? What am I missing? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Mathias Gaunard wrote:
Joel de Guzman wrote:
Can you do "emplace" without move-construct? With a non-C++0x compiler? What am I missing?
Well, Boost.optional has been doing it for years already. The only problem is correctly forwarding the arguments of the constructor.
Ah yeah right. I forgot about that. Ok, I'll look into it. I also welcome contributions, if you guys have some spare time and want to do some hacking :-) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman <joel <at> boost-consulting.com> writes:
Hmm... well... a) How do you put a noncopyable object in a container? b) How do you copy a container with noncopyable elements?
what i really wanna do is not to name the objects i put i the fusion vector. they should be constructed in place and only be accessed through the fusion vector. should look something like this: typedef boost::fusion::vector<JobA, JobB, JobC> tJobs; struct System { System(Da& da) : fJobs(JobA(da), JobB(da, 2), JobC(da, 3)) {} private: tJobs fJobs; }; there are several operations that need to include all jobs - non has to be left out - and to avoid repetitive coding, it would be nicer to only operate on fJobs.
Fusion vector is based on stl vector. Even stl vector requires copy constructible types.
One possibility is to store your object in a smart pointer or wrap it in a reference wrapper. Then, the smart pointer and reference wrapper can be stored in the fusion container.
but doesn't it make a difference that the stl sequences are runtime-extensible? you always get an empty sequence and add to it at runtime. with fusion::vector, i know exactly in advance how many objects i need to create (i mean at compile time), and i have to explicitly call the constructor in the initialization list. from this point of view i thought it rather behaves like the initialization of an array.

AMDG oliver wrote:
what i really wanna do is not to name the objects i put i the fusion vector. they should be constructed in place and only be accessed through the fusion vector. should look something like this:
typedef boost::fusion::vector<JobA, JobB, JobC> tJobs; struct System { System(Da& da) : fJobs(JobA(da), JobB(da, 2), JobC(da, 3)) {} private: tJobs fJobs; };
This exact syntax cannot be implemented without a copy constructor. JobA(da) creates a temporary JobA which is then copied into the fusion::vector. You would have to use something like fJobs(boost::in_place(da), boost::in_place(da, 2), boost::in_place(da, 3)) In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
oliver wrote:
what i really wanna do is not to name the objects i put i the fusion vector. they should be constructed in place and only be accessed through the fusion vector. should look something like this:
typedef boost::fusion::vector<JobA, JobB, JobC> tJobs; struct System { System(Da& da) : fJobs(JobA(da), JobB(da, 2), JobC(da, 3)) {} private: tJobs fJobs; };
This exact syntax cannot be implemented without a copy constructor. JobA(da) creates a temporary JobA which is then copied into the fusion::vector. You would have to use something like
fJobs(boost::in_place(da), boost::in_place(da, 2), boost::in_place(da, 3))
Ok, thanks to other folks for reminding me of in_place_factory. So, yes, in_place is indeed the solution here. I'm not sure though when I can have the time to actually implement it, so first, I'll ask the OP (Oliver Mueller) to add a trac ticket for this item. In the meantime, I welcome contributions. Implementing this shouldn't be too hard, but it involves modifying a couple of container classes to take in the lazy factories. Hmmm... come to think of it, a lot of fusion functions can also take advantage of it (push_back, etc.). Any takers? ;-) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman <joel <at> boost-consulting.com> writes:
Ok, thanks to other folks for reminding me of in_place_factory. So, yes, in_place is indeed the solution here. I'm not sure though when I can have the time to actually implement it, so first, I'll ask the OP (Oliver Mueller) to add a trac ticket for this item.
trac ticket added.
In the meantime, I welcome contributions. Implementing this shouldn't be too hard, but it involves modifying a couple of container classes to take in the lazy factories. Hmmm... come to think of it, a lot of fusion functions can also take advantage of it (push_back, etc.).
Any takers?
Regards,
since i need it i will try to get something working for vector first...hope there is not too much preprocessor magic going on in there:)

oliver wrote:
Joel de Guzman <joel <at> boost-consulting.com> writes:
Ok, thanks to other folks for reminding me of in_place_factory. So, yes, in_place is indeed the solution here. I'm not sure though when I can have the time to actually implement it, so first, I'll ask the OP (Oliver Mueller) to add a trac ticket for this item.
trac ticket added.
In the meantime, I welcome contributions. Implementing this shouldn't be too hard, but it involves modifying a couple of container classes to take in the lazy factories. Hmmm... come to think of it, a lot of fusion functions can also take advantage of it (push_back, etc.).
Any takers?
Regards,
since i need it i will try to get something working for vector first...hope there is not too much preprocessor magic going on in there:)
Haha! Hide, Joel, hide!!! :-) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
oliver wrote:
Joel de Guzman <joel <at> boost-consulting.com> writes:
Ok, thanks to other folks for reminding me of in_place_factory. So, yes, in_place is indeed the solution here. I'm not sure though when I can have the time to actually implement it, so first, I'll ask the OP (Oliver Mueller) to add a trac ticket for this item.
trac ticket added.
In the meantime, I welcome contributions. Implementing this shouldn't be too hard, but it involves modifying a couple of container classes to take in the lazy factories. Hmmm... come to think of it, a lot of fusion functions can also take advantage of it (push_back, etc.).
Any takers? Regards,
since i need it i will try to get something working for vector first...hope there is not too much preprocessor magic going on in there:)
Haha! Hide, Joel, hide!!! :-)
Seriously, thanks in advance! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Steven Watanabe <watanabesj <at> gmail.com> writes:
oliver wrote:
typedef boost::fusion::vector<JobA, JobB, JobC> tJobs; struct System { System(Da& da) : fJobs(JobA(da), JobB(da, 2), JobC(da, 3)) {} private: tJobs fJobs; };
This exact syntax cannot be implemented without a copy constructor. JobA(da) creates a temporary JobA which is then copied into the fusion::vector. You would have to use something like
fJobs(boost::in_place(da), boost::in_place(da, 2), boost::in_place(da, 3))
i wasn't aware of boost::in_place, thanks for pointing that out. i guess that is as good as it gets...or can get...although something like this would of course be almost too sweet: fJobs(da, (da, 2), (da, 3)) anyway, the in_place solution is very appealing to me.

Joel de Guzman wrote:
Hmm... well... a) How do you put a noncopyable object in a container?
Two possibilities: - You construct directly the object within the container, which is preferred, since optimal. As I said later in the thread, optional has been using this technique for ages by taking an unary functor taking an address. The right functor can then be generated by in_place<T>(args...) (which is actually quite similar to "construct" in lambda/phoenix). The technique used in C++0x containers (placement insert paper) is different though, the insertion (insert/push_*) functions are replaced (except insert, due to ambiguities, so the alternative version is called "emplace") to take the args of the constructor directly. It's way less compile-time efficient and generic, but supposedly it's easier to use. (I personally fail to see how, v.push_back(in_place(args...)) isn't more difficult than v.push_back(args...), and there would be no ambiguity). - You move an already constructed object, which may be cheaper than copying it or not. Most objects are movable though, which is not the case for copying.
b) How do you copy a container with noncopyable elements?
You do not. A container of copyable elements is copyable. A container of movable elements is movable. A container of non-movable elements may be movable or not.
Fusion vector is based on stl vector. Even stl vector requires copy constructible types.
And that's a major defect of the STL. I'm personally quite looking forward to the containers with move semantics and placement insert that Ion Gaztanaga is working on (I hope he still is).
One possibility is to store your object in a smart pointer or wrap it in a reference wrapper.
A fairly high price to pay to work around an obvious defect IMO. I know a few people that have been using zero-sized vectors but with some capacity so that they could directly construct their objects in it. An ugly hack, but at least it works as expected.
participants (6)
-
David Abrahams
-
Joel de Guzman
-
Mathias Gaunard
-
oliver
-
Oliver Mueller
-
Steven Watanabe