Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2004-01-29 08:38:50


Hi Jim,

> I was a little unclear last time: by deep const I mean
> something<const T>
> is the correct indication of const, whereas by shallow const I mean
> const comething<T>
> is the correct indication of const.
>
I see.

AFAIK, "deep" X means that when an outer object has property X,
its inner objects must have X too; while "shallow" X means that
the X property of the outer object is not promoted to the
inner objects.

For example, deep-const for a wrapper W<T> implies that:

char const* test ( T const& ) { return 'const' ; }
char const* test ( T& ) { return 'mutable' ; }

W<T> w;
W<T> const wc;

test(w);
test(wc);

should output:

const
mutable

While "shallow-const" implies that the output is:

mutable
mutable

OTOH, *I* call "preserving" X when the value of X for the inner object
is independent of the value of X for the outer object.
Most template wrappers are preserving in this sense because cv-qualifiers
are preserved.
For example, preserving-const implies that:

W<T> w;
W<T const> cw;

test(w);
test(cw);

outputs:

mutable
const

A deep-const wrapper with preserving-const will be such that:

W<T> w;
W<T> const wc;
W<T const> cw;
W<T const> const cwc;

test(w);
test(wc);
test(cw);
test(cwc);

outputs:

mutable
const
const
const

value_initialized<> is a shallow-preserving-const wrapper:

value_initialized<T> w;
value_initialized<T> const wc;

value_initialized<T const> cw;
value_initialized<T const> const cwc;

test(w);
test(wc);
test(cw);
test(cwc);

outputs:

mutable
mutable
const
const

Is this the behaviour you want?

> Fernando Cacciola wrote:
> > It would be very confusing if constantness semantics were to change
> > depending on the compiler.
>
> That's true. Broken const semantics are a problem though, especially
> the conversion operator. What if the working compilers had the member
> functions (data and operator T &, perhaps operator->) and non working
> compilers only had get?
>
This could be done, yes.

> >>For those compilers, I think there would be value to adding operator->
> >>for the invocation of member functions, like boost::optional.
> >
> > I'm not sure.
> > operator-> generated a long discussion because of its implied pointer
> > semantics.
> > In the case of boost::optional<>, the possibility of the uninitialized
> > state is my corner argument in favot of it.
> > Yet with value_initialized<> I can't see any favorable argument.
>
> I suppose it depends on your POV. I find get(x).f() and x.data().f()
> much less clear than x->f(). The reason I find the latter more clear is
> that it is clear that f is a member function in x's type. get(x)
> required me to find the get by human-driven ADL, and x.data() looks like
> I'm acting on a part of x.
>
It's definitely a POV issue.
I personally am not so troubled with operator->, but I know my boosters :-)
OTOH, get(w) is a very common idiom used by lots of wrappers and,
while "x.data()" looks like acting on a part of x, which is exactly what
it's doing, "x.data().foo()" OTOH definitely looks like acting on X's data,
not X itself.

Anyway, data() should be renamed to get() for uniformity with all the other
wrappers.

> >>As an alternative, deep-copy would break const expectations in generic
> >>functions that take a const T &, but it would preserve it elsewhere, so
> >>it may be worth some more thought.
> >
> > Yes, though value_initalized is a value wrapper, so it must have deep-copy.
>
> should have been "deep const". To rehash, that means deep const
> semantics do the wrong thing in
>
> template<typename T>
> void g(const T & a) {/*whatever*/}
>
Whether its does the wrong thing or not depends on the nature of the wrapper.
In general, value-wrappers should be deep-const, and that will do the right thing
because T, being a value-wrapper for U, is intended to behave most like U.

> but can have the member functions, including conversion, without any
> worries about older compilers screaming ambiguity.
>
> > If you can guarantee proper initialization for any compiler were it is available,
> > I'd say yes, I'm interested.
>
> I will need someone else to do some testing for me. I'll post a
> candidate soon.
>
Great

> >>Should it have shallow or deep const semantics?
> >
> > Deep const, as it is a value wrapper (and not a pointer wrapper)
>
> Huh?
>
Most value-wrappers are used to extend/shrink an object's interface,
or to better define some part of its behavior.
In this case, the rest of the wrapped object should be promoted as is
to the wrapper so that usage is transparent.
In your case, you are fixing an initialization problem, so the wrapper
must look like that wrapped in every other respect.
This requires deep semantics (const and copy)

Fernando Cacciola
SciSoft


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk