Boost logo

Boost :

From: Joel de Guzman (joel_at_[hidden])
Date: 2007-11-22 03:52:44


shunsuke wrote:
> Joel de Guzman wrote:

>> alas, this uncovers a bug in the implementation where value_at
>> does not follow above.
>
> What is a bug?

See diff of the source in value_at_impl.hpp for the last 2
revisions.

> Is there any pitfall if `value_at` is the same as `at` under transform_view?

After some more thinking, yes.

>> You got me thinking though. It could very well be that you are correct!
>> Perhaps we need the same behavior for both at/deref and value_at/value_of.
>> My thinking, OTOH, is that both should get the value_at of the underlying
>> sequence. Hence, transform(vector<int, int&>, f) will trigger
>> f this way:
>>
>> int ---> f::result<f(int)>
>> int& ---> f::result<f(int&)>
>
> No, when vector<int, int&> is mutable lvalue,
> f should be able to access the mutable int.
> Hence,
>
> int --> f::result<f(int&)>
> int& --> f::result<f(int&)>

I think you are missing the point. It is always mutable with deref and at.
value_at and value_of should allow you to get the *actual* type of
the underlying sequence. Think of value_at and value_of as having
copy semantics.

> The current deref works like this unless as_vector is used.
> It's ok.

That is because as_vector needs to know the actual type of the
underlying sequence, hence it uses value_at/value_of. as_vector
*copies* the source sequence.

> Again,

[snip]

>
> Here, as_vector calls value_of. Hence,
>
> int --> f::result<f(int)>
>
> My poor identity doesn't compile.
> IMHO, as_vector should be able to return vector<int&, int&>.
>
> Once as_vector intervenes, FunctionObject can't access mutable elements in a tuple.
> For example, mutable STL iterator can't be returned from std::string in a tuple.

After some thinking, I am now convinced that the current behavior
is still the proper way to do it. I added an attachment in the
trac ticket that provides the correct way to do the identity
transform. Mutability is not lost; never was. In the case of
as_vector, a copy is generated, not a reference to the original.
This copy has the *exact* same element types of the source
sequence. If value_at were to do as at, then there is no way to
do as_vector correctly if the source vector has a reference element.

Here's a synopsis of what's being returned by at/deref and
value_at/value_of given a vector<int, int&>:

     index element type at/deref value_at/value_of
     0 T T& T
     1 T& T& T&

Notice that value_at/value_of always returns the exact type of
the element. We should not deviate from that behavior. When
a transform is used, it should do the same. Here's what's
happening (given F as the transform function):

     index element type at/deref value_at/value_of
     0 T F(T&) F(T)
     1 T& F(T&) F(T&)

This, I repeat, is the only sensible behavior. If we make
value_at/value_of behave the same as at/deref, then we can
never know the exact type of the elements in the source
container if there are references involved. Given the
"corrected" identity transform I attached in the trac ticket,
the result of the as_vector will be as expected:

      vector<int, int&>

(Both vector<int&, int&> and vector<int&, int&> results
are wrong)

For reference, here's the corrected identity transform:

     struct identity
     {
         template <class FunCall>
         struct result;

         template <class Fun, class T>
         struct result<Fun(T)>
         {
             typedef T type;
         };

         template <class T>
         T& operator()(T& val) const
         {
             return val;
         }

         template <class T>
         T const& operator()(T const& val) const
         {
             return val;
         }
     };

Regards,

-- 
Joel de Guzman
http://www.boost-consulting.com
http://spirit.sf.net

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