Re: [boost] [optional] std::tr2::optional

* Conversion explicit conversion to bool should be declared as explicit.
Doesn't an explicit conversion disallows to use it in a conditional expression as in if(opt) {}
I believe that the primary motivation for the explicit conversion operators was to provide a simpler alternative for safe-bool idiom, and address cases like this one. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf
* Should exception safety guarantees for assignment operations be enforced? In boost::optional they only provide a basic guarantee. One option is to provide strong guarantee for types T which implement operator= with strong guarantee, and give basic guarantee for other cases Other option (not sure if it is possible) is to provide strong guarantee for all cases at the cost of run-time performance (heap allocation).
Provide the same exception guaranties as the T assignment seems the more reasonable.
My apologies, I wrote this in a hurry an didn't make myself clear. There are three cases to consider (leaving move assignment and no-throw copyable types aside): 1. Our stored type T provides a strong assignment - the choice is obvious: optional<T>'s assignment is also strong 2. T has "basic" assignment - the natural choice is to provide also a basic guarantee for optional<T>'s assignment. 3. T is neither copyable nor moveable -- it is like a scope guard, or boost::scoped_ptr. In this case optional<T> still provides assignment by making a "pseudo destructor call" followed by a call to placement new. -- but this gives only basic guarantee. The question is if for this third variant we should be happy with only basic guarantee or to use a trick boost::variant is using with auxiliary heap-allocated object? (I do not even know if this is applicable though).
template< typename ... Args> optional( Args&& ...args ); I like them. The constructor will clash with another optional constructor: optional<T>::optional( bool cond, const T& val );
I don't understand why.
Currently boost::optional provides this constructor: optional<T>::optional( bool cond, const T& val ); If cond is true the optional is initialized with object val, otherwise it is uninitialized. Now suppose I have a following type: struct MyType { bool on; int m1; int m2; MyType( bool on, MyType const& rhs ) :on{on}, m1{rhs.m1}, m2{rhs.m2} {} }; MyType mt { true, 1, 2 }; boost::optional<MyType> o1{ true, mt }; // optional initialized with mt (copy ctor used) boost::optional<MyType> o2{ boost::in_place(true, mt) }; // uses 2-arg ctor But if std::tr2::optional has "variadic" constructor: std::tr2::optional<MyType> mt{ true, mt }; // uses 2-arg ctor Regards, &rzej

On 18 November 2011 15:16, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
3. T is neither copyable nor moveable -- it is like a scope guard, or boost::scoped_ptr. In this case optional<T> still provides assignment by making a "pseudo destructor call" followed by a call to placement new. -- but this gives only basic guarantee.
The guarantee is strong if the placement delete/new are marked noexcept, isn't it? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On 19.11.2011, at 00:16, Andrzej Krzemienski wrote:
* Should exception safety guarantees for assignment operations be enforced? In boost::optional they only provide a basic guarantee. One option is to provide strong guarantee for types T which implement operator= with strong guarantee, and give basic guarantee for other cases Other option (not sure if it is possible) is to provide strong guarantee for all cases at the cost of run-time performance (heap allocation).
Provide the same exception guaranties as the T assignment seems the more reasonable.
My apologies, I wrote this in a hurry an didn't make myself clear. There are three cases to consider (leaving move assignment and no-throw copyable types aside): 1. Our stored type T provides a strong assignment - the choice is obvious: optional<T>'s assignment is also strong 2. T has "basic" assignment - the natural choice is to provide also a basic guarantee for optional<T>'s assignment. 3. T is neither copyable nor moveable -- it is like a scope guard, or boost::scoped_ptr. In this case optional<T> still provides assignment by making a "pseudo destructor call" followed by a call to placement new. -- but this gives only basic guarantee. The question is if for this third variant we should be happy with only basic guarantee or to use a trick boost::variant is using with auxiliary heap-allocated object? (I do not even know if this is applicable though).
Do we even want the third variant? That is, do we want to support tr2::optional of something that is neither copyable nor movable? My gut instinct says no, that's unintuitive. Sebastian

On 19 November 2011 02:22, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Do we even want the third variant? That is, do we want to support tr2::optional of something that is neither copyable nor movable?
I think we do. optional<T> should be copyable if and only if T is copyable, and optional<T> should be moveable if and only if T is moveable. (I'm not yet sure if construction vs. assignment can also be distinguished based on how we can implement it.) -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Saturday, November 19, 2011 11:22:25 Sebastian Redl wrote:
On 19.11.2011, at 00:16, Andrzej Krzemienski wrote:
3. T is neither copyable nor moveable -- it is like a scope guard, or boost::scoped_ptr. In this case optional<T> still provides assignment by making a "pseudo destructor call" followed by a call to placement new.
Do we even want the third variant? That is, do we want to support tr2::optional of something that is neither copyable nor movable? My gut instinct says no, that's unintuitive.
Why not? I've had such use cases and I don't see why that would be wrong.

On Saturday, November 19, 2011 00:16:43 Andrzej Krzemienski wrote:
3. T is neither copyable nor moveable -- it is like a scope guard, or boost::scoped_ptr. In this case optional<T> still provides assignment by making a "pseudo destructor call" followed by a call to placement new. -- but this gives only basic guarantee. The question is if for this third variant we should be happy with only basic guarantee or to use a trick boost::variant is using with auxiliary heap-allocated object? (I do not even know if this is applicable though).
I think, heap-allocated storage is not acceptable since it defeats the whole purpose of optional in this case. The user could have used unique_ptr (or whatever other pointer) from the beginning to handle this case. What optional provides is the effective in-place storage. Basic guarantee is the best we can provide in this case and this is great. Because normally there would be no assignment at all.
The constructor will clash with another optional constructor: optional<T>::optional( bool cond, const T& val );
I don't understand why.
Currently boost::optional provides this constructor: optional<T>::optional( bool cond, const T& val ); If cond is true the optional is initialized with object val, otherwise it is uninitialized.
Now suppose I have a following type:
struct MyType { bool on; int m1; int m2; MyType( bool on, MyType const& rhs )
:on{on}, m1{rhs.m1}, m2{rhs.m2} {}
};
MyType mt { true, 1, 2 }; boost::optional<MyType> o1{ true, mt }; // optional initialized with mt (copy ctor used) boost::optional<MyType> o2{ boost::in_place(true, mt) }; // uses 2-arg ctor
But if std::tr2::optional has "variadic" constructor: std::tr2::optional<MyType> mt{ true, mt }; // uses 2-arg ctor
I think, this constructor with bool is excessive because there is no problem in checking for the flag in the user's code before constructing the value. This would even save the wasted construction of the value if the flag is false. What's really missing is the variadic assign method that would allow in-place construction of values in an existing optional. So the example you described would look like this: optional< MyType > opt; if (should_exist) opt.assign(true, 1, 2); // these arguments are passed to MyType ctor
participants (4)
-
Andrey Semashev
-
Andrzej Krzemienski
-
Nevin Liber
-
Sebastian Redl