|
Boost : |
From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2002-11-22 13:22:13
----- Original Message -----
From: "Vincent Finn" <vincent_finn_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, November 22, 2002 1:38 PM
Subject: [boost] Re: Formal Review Request: class optional<>
> Hi,
>
> I have one comment and one question.
> So first the comment
>
> I was recently thinking about a similar thing for a slightly different
> purpose. You seem to concentrate on option return values, what about
> optional arguments.
>
> e.g.
> void fn(int iImportant, optional<int> iNotImportant = optional<int>());
>
> The reasoning for this is similar to for the return
> the function could tell if the user had passed in an argument and act
> accordingly
>
> Normally you can have a special default value but cases can occur where
> and int is valid but none might be required.
>
Good point. On a few ocasions I have use optional<> to pass optional
parameters.
However, I've came to the following:
Take you example for instance:
void fn(int iImportant, optional<int> iNotImportant = optional<int>())
{
if ( !!iNotImportant )
{
// not important argument recieved, use it.
foo ( * iNotImportant ) ;
}
}
Since optional<> uses pointer semantics, the above code could have been
written using a true pointer with nearly the same syntatic usage of the
optional parameter:
void fn(int iImportant, int* iNotImportant = NULL )
{
if ( !!iNotImportant )
{
// not important argument recieved, use it.
foo ( * iNotImportant ) ;
}
}
So, from the recieving function perspective, there is little -if any-
benefit in using optional<> for this.
The NULL default value for the pointer is idiomatic enough to document the
fact that the parameter is optional.
Now, from the caller perspective, using a pointer parameter has a drawback:
the parameter must be an lvalue (it requires storage), so you can't write:
fn(1,&3)
and you are forced to use a local variable:
int b=3;
fn(1,&b);
However, the true problem here is not that using a pointer in the function
signature is cumbersome, but that passing it can be problematic if we want
to use a literal (let's assume that prefixing '&' is not big deal).
I've found more convenient to solve this specific problem instead of
cluttering a function interface with optional<> as a parameter.
For example, if the optional parameter is constant:
void foo ( int const* x = NULL ) ;
You can pass literals on the fly using the following helper:
template<class T> T const& lvalue( T const& v ) { return v; }
int main()
{
foo(&lvalue(3));
}
And if the optional parameter is not constant, you can use a more
sophisticated helper:
template<class T>
struct lvalue_wrapper
{
lvalue_wrapper( T val ) : data(val) {}
operator T&() const { return data ; }
T* operator &() const { return &data ; }
mutable T data ;
} ;
template<class T>
lvalue_wrapper<T> lvalue( T v ) { return lvalue_wrapper<T>(v) ; }
void bar( int* x = NULL ) ;
int main()
{
foo(&lvalue(3));
bar(&lvalue(3));
}
Concluding, I think optional<> is not really necessary for optional
parameters since these can be expressed very well by a true pointers and
that the calling syntax can be arranged to be simple .
> The reason I assume you don't allow for this is that your constructor is
> explicit and for easier calling sytax in this case that would not be
> best (I think)
> i.e. I would want to be able to call the above as
> fn(1, 3);
>
The constructor must be explicit in order to disable unexpected implicit
conversions.
If you happen to use optional<> in a parameter list, you can always pass it
using:
fn(1, optional<T>(3));
> The most common reason, though, would be the desire to use references
> rather than pointers
> int fn1(optional<int&> iMayNotWant = optional<int&>());
> instead of
> int fn2(int* piMayNotWant = NULL);
>
Notice that optional<> itself has pointer semantics, so you wouldn't be able
to handle "iMayNotWant" by value as you would if it were a reference; you
would handle it exactly as you would if it were a true pointer.
This is by it rarely makes sense to have optional<> in a parameter list.
> I assume this isn't possible since references aren't default
> constructable but it would be nice :-)
>
Actually, optional<T> does not require T to be default constructable.
The reason why you can't have optional<T&> is -at least- that you cannot
have a reference to a reference,
and optional<T> uses "T {const} &" (for example, in the constructor).
> ---
>
> And now the question
> can this be used with VC6 ?
>
Yes, that's my intention.
I will see to make it compile with all compilers I receive reports from.
Which version of VC6 are you using?
> I have tried at it won't compile (I'm compiling with boost 1.29)
> I get the following error in optional
>
> optional_detail.hpp(91) : error C2371: 'proxy' : redefinition; different
> basic types
> optional_detail.hpp(90) : see declaration of 'proxy'
> optional_detail.hpp(171) : see reference to class template
> instantiation 'boost::optional_detail::value_based_optional<T>' being
> compiled
>
> and lots of errors in
> mpl\logical\and.hpp
> e.g
> mpl\logical\and.hpp(115) : error C2039: 'type' : is not a member of
> '`global namespace''
> mpl\logical\and.hpp(115) : error C2146: syntax error : missing ','
> before identifier 'value'
>
> and a lot more :-(
>
>
OK. I think I have a VC6.5 or some around. I'll see how to fix it.
Best Regards,
Fernando Cacciola
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk