Boost logo

Ublas :

From: Ian McCulloch (ianmcc_at_[hidden])
Date: 2005-08-25 13:06:17


Michael Stevens wrote:

> Hello again Gunter,
>
> On Wednesday 24 August 2005 14:33, Gunter Winkler wrote:
>> Hello,
>>
>> does anyone have an idea why
>>
>> matrix_column<triangular_matrix<DBL, lower> > cLk(L, 1);
>> project( cLk, range(2, 3) )
>> = project( column(A, 2), range(2, 3) );
>>
>> compiles fine, but
>>
>> project( column(L, 2), range(2, 3) )
>> = project( column(A, 2), range(2, 3) );
>>
>> complains about discarding 'const' qualifier of column(L, 2)?
>
> This is a problem I have been worrying about for a while.
>
>> Is the type of column(L, 2) a const range even if L is non-const?
>
> column(L,2) returns a non-const matrix_column. In this context however,
> this return value is a temporary object. Temporary objects can only be
> passed as const references. Therefore the const version of project is
> called in the latter case.
>
> This is a fundamental problem with the current implementation of uBLAS
> proxies. They propagate (as a normal object would) this constantness to
> their operations. This is advantageous in that it is consistent with other
> objects and provides error messages at a relatively high level in the
> instaneation hierarchy.
>
> However is prevents all the projection free functions being used in a
> nested form. I would like to experiment with changing the proxies so they
> respect only the constantness of the object the close on. I'm not really
> sure what wider impact this will have.
>
> It would be interesting to here how other libraries deal with the problem
> of closures as temporary return values. MTL3, GLAS anyone?

I get around it with a hack: a metafunction is_mutable_proxy<T> that returns
mpl::true_ iff T is a non-const proxy (or reference) to a non-const (in
this scheme I regard 'proxy<U const>' and 'const proxy<U>' as equivalent,
so is_mutable_proxy<T const> is always false_). Then

template <typename T>
void
some_function(T& x) { ... }

template <typename T>
inline
typename boost::enable_if<is_proxy_reference<T> >::type
some_function(T const& x)
{
   some_function(const_cast<T&>(x));
}

I am optimistic that rvalue references will eventually make it into C++,
then the hackery will go away and it will simply be

template <typename T>
void
some_function(T&& x) { ... }

Not sure if it is a good idea for uBLAS to go down this route, it uses a lot
of SFINAE and a whole suite of metafunctions to keep track of const
correctness (and even then it is only approximately const-correct, because
of the const_cast hack).

A simpler way might be to ignore the top-level const and simply have
proxy<T> and proxy<T const>. Then the const_cast hack above is actually
correct ;) But then it is not possible convert a non-const proxy into a
const-proxy. Maybe that doesn't matter much for uBLAS? For me it wasn't
really an option, as many of my container classes are copy-on-write
reference counted.

Cheers,
Ian