|
Boost : |
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2007-07-23 22:33:43
On 7/23/07, Eric Niebler <eric_at_[hidden]> wrote:
>
> General design question here. This came up on the user's list, and it
> made me question something I believed to be true. When writing a proxy
> for, e.g., a std container, I see two options for handling const.
>
> 0) Const-ness depends on the const-ness of the object being proxied:
>
> 1) Const-ness depends on the proxy object itself:
>
I suppose it really depends on context and how exactly you wish to deal with
the proxy, but I would personally try to keep semantics as close as possible
to a reference type. You can't directly create a reference type with
cv-qualification, and by convention, metafunctions which add
cv-qualification to reference types generally yield the input reference type
unmodified (such as in Boost.Type_Traits). You obviously can't mimic the
former behavior, but to come as close as possible to reference behavior, I'd
make cv-qualification of the proxy type not impact the view of the proxied
object, and instead make it as much of an implementation detail as possible.
Jumping away for a second, given a reference to a vector as a datamember to
some type, when this encapsulating type becomes const-qualified, your
reference datamember does not all of a sudden reference the vector as though
it were const-qualified. Similarly, if you have a proxy to a vector as a
datamember, when the encapsulating type becomes const-qualified, your proxy
should not all of a sudden reference the vector as though it were
const-qualified. You are still dealing with reference semantics so the
top-level qualification should not propogate. Because of this, I'd say 0 is
the better approach, or at least the most consistent approach with respect
to the rest of the language.
Honestly, though, I'm not in love with either
approach. As I said, I would prefer 0 over 1, but 0's definition of
vector_proxy::const_iterator is still troubling to me. Perhaps for practical
reasons, such as use with certain generic algorithms, it may make sense to
have
vector_proxy::const_iterator be the same type as std::vector<int>::iterator
as you have shown, but if you absolutely must have the typedef present,
I would personally more intuitively prefer it to be the same type as
std::vector<int>::const_iterator, though still only provide the single
begin() const with a return type of iterator. It really depends on how the
proxy is used and what behavior your algorithms expect from the proxies.
While likely not practical for
many cases, I would even consider a third option, and that is to
not include the nested typedefs at all. After all, there is no such thing as
std::vector<int>&::iterator. For the sake of hacking together proxies that
work with algorithms which expect STL containers, providing the nested
typedefs may be the only option to optimize code reuse, but in those cases,
you have to
realize that what you would be doing truely is a hack, since a proxy itself
is not a valid STL container type and therefore shouldn't be passed to
algorithms where one is expected.
-- -Matt Calabrese
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk