[optional] new assignmet semantic and references

Hello people, A few days ago, a problem with Boot.Optional's assignment not properly handling aliasing scenarios (like self assignment) was pointed out. We concluded that the solution was to use T's operator=() directly instead of the Destroy+Construct pattern that I was using. I changed the code, tested it, and I was updating the documentation when I recalled the following long-standing issue: Currently, with the Destroy+Construct pattern, references are re-bound in case of assignment: int a = 123 ; int b = 456 ; int& ra = a ; int& rb = rb ; optional<int&> ora(ra); optional<int&> orb(rb); ora = orb ; // now 'ora' contains a reference to 'b' instead of 'a' b = 789 ; cout << *ora ; Prints 789 cout << a ; Prints 123 This is not the way assignment of reference types work in C++: ra = rb ; // The value of 'a' referenced by 'ra' is changed, not the reference itself. cout << a ; Prints 789 This error in the way optional<T&> treated assignment of reference types was pointed out by Joel de Guzman long ago when he started using Optional in Spirit. However, at the time, Joel explicitely asked me not to change this and keep the current rebinding semantics in order to minimize any impact in Spitit itself (which certainly has, o had, a much larger user base). If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted. Note: if you look at Optional documentation you will discover that assignment is only documented for T not being of reference type. This was intentional.. I left this undocumented becasue I knew back then that the current semantics were wrong but I couldn't fix it at the time because Spirit was (or could be) depending on it; yet I didn't want other users to depend on it as well... Of course, users could have "discovered" the (incorrect) semantics themselves and now rely on it, but I hope that the intentionally missing documentation served to keep the amount of users depending on this incorrect semantics very low. [At least it served _me_ to remember about this since I had forgotten] I really want to 'fix' this, i.e, give it correct semantics, so unless Joel or anyone else speaks now I'll move on, finish the documentation updates and commit the new version. Best, Fernando Cacciola

"Fernando Cacciola" <fernando_cacciola@hotmail.com> writes:
This is not the way assignment of reference types work in C++:
ra = rb ; // The value of 'a' referenced by 'ra' is changed, not the reference itself. cout << a ; Prints 789
This error in the way optional<T&> treated assignment of reference types was pointed out by Joel de Guzman long ago when he started using Optional in Spirit. However, at the time, Joel explicitely asked me not to change this and keep the current rebinding semantics in order to minimize any impact in Spitit itself (which certainly has, o had, a much larger user base).
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
You might want to consider whether it makes sense to change the semantics only for non-reference types. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> escribió en el mensaje news:uzmxnnzi1.fsf@boost-consulting.com...
"Fernando Cacciola" <fernando_cacciola@hotmail.com> writes:
[SNIP]
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
You might want to consider whether it makes sense to change the semantics only for non-reference types.
Yes, I considered that.. the problem I have is that I really don't like Optional rebinding references upon assignment... its ideal principle is to do exactly as the wrapped type does and differ only when uninitialized cases are involved. The current fix is a step towards that. So I think I will fix it unless users speak up... Though I will post this issue in the users list as well. Btw, wouldn't it be very useful to have some sort of mechanism to allow users to register to boost or a particular boost library? that way we could broadcast a warning or a request to input feedback whenever we need to make a decision like this. Fernando Cacciola

"Fernando Cacciola" <fernando_cacciola@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> escribió en el mensaje news:uzmxnnzi1.fsf@boost-consulting.com...
"Fernando Cacciola" <fernando_cacciola@hotmail.com> writes:
[SNIP]
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
You might want to consider whether it makes sense to change the semantics only for non-reference types.
Yes, I considered that.. the problem I have is that I really don't like Optional rebinding references upon assignment... its ideal principle is to do exactly as the wrapped type does and differ only when uninitialized cases are involved.
It depends on whether you view optional<T> as a T that might just happen to be missing, or as a container for a T. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Behalf Of Fernando Cacciola Sent: Tuesday, March 01, 2005 10:39 AM To: boost@lists.boost.org Subject: [boost] Re: [optional] new assignmet semantic and references
So I think I will fix it unless users speak up... Though I will post this issue in the users list as well.
First I'd like to say that I love optional<>. When I first read about it I didn't think I'd use it much, but now I find myself using it all over the place. It's useful for so many things, but to me the most important is how it improves my ability to make code self-documenting. Personally, I like it the way it is. I've used optional quite a bit and it makes sense to me that operator= changes what an optional holds. I don't think it is a good idea to give operator= special semantics for references. I think it odd, for instance, that given the following optionals: int a = 5, b = 6; boost::optional<int&> ra = a, rb = b; this: ra = rb; would have different behavior than: ra.reset(); ra = rb; I can understand the desire to mimic the semantics of built in C++ references in boost::optional, but one uses boost::optional precisely in cases where one does not want those semantics - in cases where a reference may not be present, and where you may want to change which object is referred too. My humble .02. Brock

"Brock Peabody" <brock.peabody@npcinternational.com> writes:
On Behalf Of Fernando Cacciola Sent: Tuesday, March 01, 2005 10:39 AM To: boost@lists.boost.org Subject: [boost] Re: [optional] new assignmet semantic and references
So I think I will fix it unless users speak up... Though I will post this issue in the users list as well.
First I'd like to say that I love optional<>. When I first read about it I didn't think I'd use it much, but now I find myself using it all over the place. It's useful for so many things, but to me the most important is how it improves my ability to make code self-documenting.
Personally, I like it the way it is. I've used optional quite a bit and it makes sense to me that operator= changes what an optional holds. I don't think it is a good idea to give operator= special semantics for references.
I had the same feeling. That's what I meant when I said "It depends on whether you view optional<T> as a T that might just happen to be missing, or as a container for a T." I think "a container for a T" is a more manageable meaning for optional<T>.
I think it odd, for instance, that given the following optionals:
int a = 5, b = 6;
boost::optional<int&> ra = a, rb = b;
this:
ra = rb;
would have different behavior than:
ra.reset();
ra = rb;
I can understand the desire to mimic the semantics of built in C++ references in boost::optional, but one uses boost::optional precisely in cases where one does not want those semantics - in cases where a reference may not be present, and where you may want to change which object is referred too.
This is what I'd have said if I'd had the time to really consider it deeply and write it out. Nice, Brock. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Brock Peabody" <brock.peabody@npcinternational.com> writes:
On Behalf Of Fernando Cacciola Sent: Tuesday, March 01, 2005 10:39 AM To: boost@lists.boost.org Subject: [boost] Re: [optional] new assignmet semantic and references
So I think I will fix it unless users speak up... Though I will post this issue in the users list as well.
First I'd like to say that I love optional<>. When I first read about it I didn't think I'd use it much, but now I find myself using it all over the place. It's useful for so many things, but to me the most important is how it improves my ability to make code self-documenting.
Personally, I like it the way it is. I've used optional quite a bit and it makes sense to me that operator= changes what an optional holds. I don't think it is a good idea to give operator= special semantics for references.
I had the same feeling. That's what I meant when I said
"It depends on whether you view optional<T> as a T that might just happen to be missing, or as a container for a T."
I think "a container for a T" is a more manageable meaning for optional<T>.
FWIW, a tuple<T&> can't be re-bound. I'll state my point again. I noticed this odd behavior of optional some years ago: giving optional re-binding semantics *is actually* giving it special semantics and requires special case handling. This leads to subtle problems like the one Fernando is experiencing now. If you want rebinding semantics, use a pointer, or use boost::ref. The right behavior, I strongly believe, is to do as the references do. This is what tuple did and we have nary a problem with it. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman
FWIW, a tuple<T&> can't be re-bound.
True, but neither can a tuple<T&> be null.
I'll state my point again. I noticed this odd behavior of optional some years ago: giving optional re-binding semantics *is actually* giving it special semantics and requires special case handling. This leads to subtle problems like the one Fernando is experiencing now.
IIUC the proposed changes do not prevent rebinding: int i = 1, j = 2; boost::optional<int&> oa = i; oa = j; //i is 2 oa.reset(); oa = j; //oa is rebound
If you want rebinding semantics, use a pointer
But optionals are so much cleaner. Given a T& your only options would be a naked pointer which would have to be unpleasantly documented or to put it in a shared pointer with a noop deleter.
, or use boost::ref.
I guess boost::optional<boost::ref<T> > would do the trick.
The right behavior, I strongly believe, is to do as the references do. This is what tuple did and we have nary a problem with it.
Maybe the right solution then is that boost::optional<T&> can only be initialized via constructor. There are really two separate issues: 1) should optional<T&> be rebindable I think it's handy to be able to rebind optional<T&> but then again, I don't see why we can't rebind regular references either other than a lack of good syntax for doing it. On the other hand, I can see that since T& isn't rebindable, making optional<T&> rebindable causes problems in generic code and I can always use optional<ref<T> > anyway. 2) should optional<T&>::op= forward to its reference when bound. I still think this is a bad idea. For one thing, you can't disallow rebinding as long as you've got an op= unless you make op= sugar for *oa =, in which case assigning to unbound optional<T&> is undefined. Regards, Brock

Brock Peabody wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman
FWIW, a tuple<T&> can't be re-bound.
True, but neither can a tuple<T&> be null.
I'll state my point again. I noticed this odd behavior of optional some years ago: giving optional re-binding semantics *is actually* giving it special semantics and requires special case handling. This leads to subtle problems like the one Fernando is experiencing now.
IIUC the proposed changes do not prevent rebinding:
int i = 1, j = 2;
boost::optional<int&> oa = i;
oa = j; //i is 2
oa.reset();
oa = j; //oa is rebound
Hmmm. I smell something wrong with that.
If you want rebinding semantics, use a pointer
But optionals are so much cleaner. Given a T& your only options would be a naked pointer which would have to be unpleasantly documented or to put it in a shared pointer with a noop deleter.
Agreed.
, or use boost::ref.
I guess boost::optional<boost::ref<T> > would do the trick.
The right behavior, I strongly believe, is to do as the references do. This is what tuple did and we have nary a problem with it.
Maybe the right solution then is that boost::optional<T&> can only be initialized via constructor.
Yes. This is what I expected. As always, when in doubt, do as the <place your primitive here>. In this case, tuple got it right: no special case handling for references. The behavior, WRT assignment and construction, should follow that of a struct with a T& member.
There are really two separate issues:
1) should optional<T&> be rebindable
I think it's handy to be able to rebind optional<T&> but then again, I don't see why we can't rebind regular references either other than a lack of good syntax for doing it.
On the other hand, I can see that since T& isn't rebindable, making optional<T&> rebindable causes problems in generic code and I can always use optional<ref<T> > anyway.
Exactly!
2) should optional<T&>::op= forward to its reference when bound.
I still think this is a bad idea. For one thing, you can't disallow rebinding as long as you've got an op= unless you make op= sugar for *oa =, in which case assigning to unbound optional<T&> is undefined.
When in doubt, do as the references do. I strongly believe that tuple, optional and variant should all have the same behavior when it comes to dealing with references. Tuple did it right. I hope optional and variant follow. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Brock Peabody wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman
FWIW, a tuple<T&> can't be re-bound.
True, but neither can a tuple<T&> be null.
Oops, I missed this. Ahem, I don't see the connection of being nullable and being rebindable. Are you trying to say that being nullable requires it to be rebindable too? I think these are two different things. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman
FWIW, a tuple<T&> can't be re-bound.
True, but neither can a tuple<T&> be null.
Oops, I missed this. Ahem, I don't see the connection of being nullable and being rebindable. Are you trying to say that being nullable requires it to be rebindable too? I think these are two different things.
That's what I was trying to say but I agree with you now that being nullable doesn't imply being rebindable. Regards, Brock

Joel de Guzman <joel@boost-consulting.com> writes:
David Abrahams wrote:
"Brock Peabody" <brock.peabody@npcinternational.com> writes:
it improves my ability to make code self-documenting. Personally, I like it the way it is. I've used optional quite a bit and it makes sense to me that operator= changes what an optional holds. I don't think it is a good idea to give operator= special semantics for references. I had the same feeling. That's what I meant when I said "It depends on whether you view optional<T> as a T that might just happen to be missing, or as a container for a T." I think "a container for a T" is a more manageable meaning for optional<T>.
FWIW, a tuple<T&> can't be re-bound.
Correct. It's all a question of what we want optional to be.
I'll state my point again. I noticed this odd behavior of optional some years ago: giving optional re-binding semantics *is actually* giving it special semantics and requires special case handling. This leads to subtle problems like the one Fernando is experiencing now. If you want rebinding semantics, use a pointer, or use boost::ref. The right behavior, I strongly believe, is to do as the references do. This is what tuple did and we have nary a problem with it.
Okay. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Jonathan Turkanis wrote:
David Abrahams wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Joel de Guzman wrote:
... This is what tuple did and we have nary a problem with it.
Do I detect a pun?
Ouch! Now I'm crosseyed?!
The pun I though I saw was "n-ary" ;-)
Interesting, but, no pun intended ;-) Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
David Abrahams wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Joel de Guzman wrote:
... This is what tuple did and we have nary a problem with it.
Do I detect a pun?
Ouch! Now I'm crosseyed?!
The pun I though I saw was "n-ary" ;-)
That's what screwed up my vision. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> escribió en el mensaje news:uy8d2p528.fsf@boost-consulting.com...
"Brock Peabody" <brock.peabody@npcinternational.com> writes:
On Behalf Of Fernando Cacciola Sent: Tuesday, March 01, 2005 10:39 AM To: boost@lists.boost.org Subject: [boost] Re: [optional] new assignmet semantic and references
So I think I will fix it unless users speak up... Though I will post this issue in the users list as well.
First I'd like to say that I love optional<>. When I first read about it I didn't think I'd use it much, but now I find myself using it all over the place. It's useful for so many things, but to me the most important is how it improves my ability to make code self-documenting.
Personally, I like it the way it is. I've used optional quite a bit and it makes sense to me that operator= changes what an optional holds. I don't think it is a good idea to give operator= special semantics for references.
I had the same feeling. That's what I meant when I said
"It depends on whether you view optional<T> as a T that might just happen to be missing, or as a container for a T."
I think "a container for a T" is a more manageable meaning for optional<T>.
This issue was there from the very beggining... It sort of reminds me about whether electrons are particles or waves... they're both, but not exactly at the same time in the usual sense... it depends on how do you _want_ to look at them. Unfortunately, optional<> is not as smart as electrons in masking themselves to the user's convenience. IMO both views are equally OK.. Each user sees pros in one and cons in the other, and there is no cut clear concensus on which one is definitely better. Yet I need to weight the balance one way and I choosen to favor the wrapper view... much of the latest evolution goes in this way.
I think it odd, for instance, that given the following optionals:
int a = 5, b = 6;
boost::optional<int&> ra = a, rb = b;
this:
ra = rb;
would have different behavior than:
ra.reset();
ra = rb;
I can understand the desire to mimic the semantics of built in C++ references in boost::optional, but one uses boost::optional precisely in cases where one does not want those semantics - in cases where a reference may not be present, and where you may want to change which object is referred too.
This is what I'd have said if I'd had the time to really consider it deeply and write it out. Nice, Brock.
Well, I agree that optional<> is intended to give you something you don't get straight from the language, but as it is now, its goal is to offer you something more of an extension of what you already get than a replacement. Furthermore, you can get rebinding semantics via optional< ref<T> >. Best Fernando Cacciola

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Fernando Cacciola
...
I think "a container for a T" is a more manageable meaning for optional<T>.
Yet I need to weight the balance one way and I choosen to favor the wrapper view... much of the latest evolution goes in this way.
...
Well, I agree that optional<> is intended to give you something you don't get straight from the language, but as it is now, its goal is to offer you something more of an extension of what you already get than a replacement.
Furthermore, you can get rebinding semantics via optional< ref<T> >.
Hi Fernando, I don't know if you saw the rest of the discussion but I think that the consensus was that rebinding should be disabled on optional<T&> as you suggest, and along with it operator=. Optional<T&> would then only be initialized via constructor (like T& itself), and optional<T&>::operator= would be a compile time error rather than deferred to T::operator=. Does this seem right to you? Brock

"Brock Peabody" <brock.peabody@npcinternational.com> escribió en el mensaje news:00ea01c525f2$73fb4e90$240a10ac@npci.com...
Hi Fernando,
Hi Brock
I don't know if you saw the rest of the discussion but I think that the consensus was that rebinding should be disabled on optional<T&> as you suggest, and along with it operator=. Optional<T&> would then only be initialized via constructor (like T& itself), and optional<T&>::operator= would be a compile time error rather than deferred to T::operator=. Does this seem right to you?
I'm not sure... I don't see a concensus on disabling operator= altoghether. That's overkill I think. But I definitely see your point about: int a = 1 ; int b = 2 ; int& ra = a ; int& rb = b ; optional<int&> opt(ra); opt = none opt = rb ; // rebinds in this case opt = ra ; // but not in this case! And I do see this as a problem. Disabling assignment to references altoghether would definitely solve this ambiguity but it can be too much of a change. Generic code just won't work anymore (because in generic code your T might happen to be a U&) I really think that optional<T&> should try to follow T& as much as possible, but you've shown that this can't be done completely because the effect of assignment directly depends on the original initialization state (that's why you drew a connection between being nullable and rebindable). The choices are: (1) Make optional<T&> non-assignable Pros: Gives optional's assignment a uniformly defined meaning. Cons: Badly breaks generic code. Badly because such code would be _forced_ to change completely as there won't by any way to make it work. If the final users feeds in a reference they'll get a compiler error unless the code uses *opt =val yet only when appropiate, which is an unlikely situation becuase if the value is going to be initialized before any assignment is _needed_ then probably optional<> isn't needed to begin with (2) Keep rebinding assignment Pros: Gives optional's assignment a uniformly defined meaning. Cons: It doesn't do as T& does, which means that current code is: (a) probably wrong (users are not aware of the odd semantic) (b) intentionally rebinding, which is odd if not unlikely (c) going to the trouble of using *opt=val to "fix" the bad semantics and exercising some rule about what to do if opt is uninitialized (which is very complex anyway) (3) Forward to operator=() WHEN THE LHS IS INITIALIZED or rebind when not Pros: Does as T& does when the lhs is initialized. Cons: Does NOT do as T& does when the lhs in uninitialized This probably means that client code still won't be able to "just" use operator=() without any regards to the prior initialization state, for if they do, the results are probably wrong. The way I see it: With choice (1) generic code won't compile unless it _only_ uses *opt=val to do assignment. With choice (3) generic code will compile but it might not do the right thing if it does not take into account the fact that the effect of assignment changes depending on the lhs state. I think that both (1) and (2) _requires_ the code to discriminate the initialization state prior to assignment, meaning that the the code will have to be of the form: if (!opt) [do something, but being aware that if opt wraps a reference you'll rebind it] else *opt = val ; The '*' is not required with choice (3) yet it is whith choice (1) In either case, ommitting it is "unnecesary" since this branch executes when opt is initialized. I don't think it is possible to avoid the pattern above and "just assign" unless you're willing to have differing effects depending on whether opt is initially empty or not. (and most likely you should NOT be willing to accept that) With choice (2) it is possible for generic code to "just assign": if it happens to be OK to rebind. If it isn't, user code must follow the same pattern above. Well, if my analysis was correct, choice (2) is the only one that doesn't _force_ ALL generic code to follow the pattern above. Thus, in spite of the fact that it breaks the rule "do as T& does" (becasue it can't follow it completely), it is the least impacting choice. What do you think? Best Fernando Cacciola

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Fernando Cacciola
I think that was an excellent analysis of the choices.
Well, if my analysis was correct, choice (2) is the only one that doesn't _force_ ALL generic code to follow the pattern above. Thus, in spite of the fact that it breaks the rule "do as T& does" (becasue it can't follow it completely), it is the least impacting choice.
What do you think?
(2) suits my personal use well because when I want something to be nullable I happen to want it to be rebindable too. From what I understand though, this is silently causing incorrect behavior in generic code. Also, it does seem to make sense to keep the concepts Rebindable and Nullable separate. I think the problems surrounding (3) rule out using it. (1) is pretty restrictive. The nice thing about its restrictiveness is that it will turn inappropriate uses into compile time errors instead runtime errors. If it does break existing code it won't do so silently. My only question is does it solve the problems that are currently being cause by (2)? BTW Fernando, I did a quick search of my code and found 991 mentions of boost::optional! Every couple of weeks I find another situation where it provides an elegant solution to a previously messy problem. I was originally pleased by optional's usefulness in communicating with other programmers but lately I've become even more excited about its ability to communicate intent to generic code. Thanks! Brock

Fernando Cacciola wrote:
Hello people,
I really want to 'fix' this, i.e, give it correct semantics, so unless Joel or anyone else speaks now I'll move on, finish the documentation updates and commit the new version.
I have no problem with change. Please do what's right and I'll adjust Spirit to suit. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Fernando Cacciola wrote:
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
Maybe boost::reference_wrapper can be used internally to wrap reference types and solve this issue. Regards, Joao

"Joao Abecasis" <jpabecasis@zmail.pt> escribió en el mensaje news:42249F77.7080402@zmail.pt...
Fernando Cacciola wrote:
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
Maybe boost::reference_wrapper can be used internally to wrap reference types and solve this issue.
How? We're not talking about an implementation problem here; this is about the "correct" behaviour and whether is ok to change to it given the potential impact on user programs. Fernando Cacciola

Fernando Cacciola wrote:
Maybe boost::reference_wrapper can be used internally to wrap reference types and solve this issue.
How?
I was suggesting the use of reference_wrapper to avoid singling out reference types everywhere in the code. The new assignment operators might just work. Anyway, I haven't tested any of this so...
We're not talking about an implementation problem here; this is about the "correct" behaviour and whether is ok to change to it given the potential impact on user programs.
I see. In that case, please disregard my previous suggestion... I'll make a new one, hopefully more helpful ;) I suggest you document how users may workaround this issue in their code using boost::reference_wrapper/ref/cref. Here's a small snippet you can use. #include <boost/optional.hpp> #include <boost/none.hpp> #include <boost/ref.hpp> int main() { int a = 32; int b = 1279; boost::reference_wrapper<int> ra(a); boost::optional<boost::reference_wrapper<int> > orw1, // default constructor orw2(boost::none), // none_t constructor orw3(ra), // value constructor orw4(boost::ref(a)); // make reference boost::optional<int &> ori1(orw1), ori2(orw2), ori3(orw3.get()); orw1 = boost::ref(b); } Best regards, João

Joao Abecasis wrote:
Fernando Cacciola wrote:
Maybe boost::reference_wrapper can be used internally to wrap reference types and solve this issue.
How?
I was suggesting the use of reference_wrapper to avoid singling out reference types everywhere in the code. The new assignment operators might just work.
Ha, well, optional<> uses make_reference_content<> (from variant<>) so I don't even need to distinguish between reference and non-reference types except were explicitely needed. In fact, the new assignment operators "just work" in this case with no need of special dispatching code.
Anyway, I haven't tested any of this so...
I suggest you document how users may workaround this issue in their code using boost::reference_wrapper/ref/cref. Here's a small snippet you can use. #include <boost/optional.hpp> #include <boost/none.hpp> #include <boost/ref.hpp>
int main() { int a = 32; int b = 1279;
boost::reference_wrapper<int> ra(a);
boost::optional<boost::reference_wrapper<int> > orw1, // default constructor orw2(boost::none), // none_t constructor orw3(ra), // value constructor orw4(boost::ref(a)); // make reference
boost::optional<int &> ori1(orw1), ori2(orw2), ori3(orw3.get());
orw1 = boost::ref(b); }
Best regards,
Nice :-) I can at least tell users how to get the "old" semantics if they really need it. Thank you! Fernando Cacciola

Joao Abecasis <jpabecasis@zmail.pt> writes:
Fernando Cacciola wrote:
If I change the code now to use T's operator=(), assignment of optional<T&> will have a _radically_ different semantics. A correct one, that's for sure, but end user code might be fundamentally impacted.
Maybe boost::reference_wrapper can be used internally to wrap reference types and solve this issue.
You might want to look at how this thread turned out. http://tinyurl.com/57axt =(http://news.gmane.org/find-root.php?message_id=%3c200212151356.42623.gregod%...) I never actually followed through on my threat to make the change, but I probably should. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (6)
-
Brock Peabody
-
David Abrahams
-
Fernando Cacciola
-
Joao Abecasis
-
Joel de Guzman
-
Jonathan Turkanis