Wrapping IList in vector-like interface

  • Thread starter Thread starter christian2.schmidt
  • Start date Start date
C

christian2.schmidt

Hi,

I'm trying to wrap an IList-instance in a native template class with a
"vector"-like interface. cliext::vector seems not suited, as it copies
the list - correct me if I'm wrong.

template <typename T>
class ClrVector {
gcroot<IList<T>^> list;
public:
ClrVector(IList<T>^ _list) : list (_list) { }
const T% operator[] (size_t i) const { return list->default; }
T% operator[] (size_t i) { return list->default; }
// ...
};

My problem is that the non-const operator[] returns a reference to a
temporary copy of the list's item. So assignments vec=x do not
work. For that I would have to call the setter of the list's default
property.

I tried a T%-wrapper for a property, by using getter and setter
delegates - but without success:

template <typename T>
ref class ReferenceWrapper
{
delegate T Getter();
delegate void Setter(T);
Getter^ getter;
Setter^ setter;
public:
ReferenceWrapper(Getter^ _getter, Setter^ _setter)
: getter (_getter), setter (_setter) { }
operator T() { return getter(); }
ReferenceWrapper<T> operator=(const T& other) {
setter(other);
return *this;
}
};

// class ClrVector<T>.operator[]:
ReferenceWrapper<T> operator[] (size_t i) {
// error:
return ReferenceWrapper said:
default::set);

}

I tried a native class, too, but delegates can only be declared in ref
classes.

Does anyone have an idea how to continue?

Thanks,
Christian
 
Hi,

I'm trying to wrap an IList-instance in a native template class with a
"vector"-like interface. cliext::vector seems not suited, as it copies
the list - correct me if I'm wrong.

template <typename T>
class ClrVector {
        gcroot<IList<T>^> list;
public:
        ClrVector(IList<T>^ _list) : list (_list) { }
        const T% operator[] (size_t i) const { return list->default;      }
        T% operator[] (size_t i) { return list->default; }
        // ...

};

My problem is that the non-const operator[] returns a reference to a
temporary copy of the list's item. So assignments vec=x do not
work. For that I would have to call the setter of the list's default
property.

I tried a T%-wrapper for a property, by using getter and setter
delegates - but without success:

template <typename T>
ref class ReferenceWrapper
{
        delegate T Getter();
        delegate void Setter(T);
        Getter^ getter;
        Setter^ setter;
public:
        ReferenceWrapper(Getter^ _getter, Setter^ _setter)
                : getter (_getter), setter (_setter) { }
        operator T() { return getter(); }
        ReferenceWrapper<T> operator=(const T& other) {
                setter(other);
                return *this;
        }

};

// class ClrVector<T>.operator[]:
        ReferenceWrapper<T> operator[] (size_t i) {
                // error:
                return ReferenceWrapper<T>(list->default::get, list->default::set);

        }


It would seem that you could make it work if you had hardcoded the
getter and setter here instead of passing them as parameters - since
you just want to wrap the Item property for IList<T>, why not do that?
 
Hi Pavel,

thanks for your answer.

// class ClrVector<T>.operator[]:
ReferenceWrapper<T> operator[] (size_t i) {
// error:
return ReferenceWrapper<T>(list->default::get, list->default::set);
}


It would seem that you could make it work if you had hardcoded the
getter and setter here instead of passing them as parameters - since
you just want to wrap the Item property for IList<T>, why not do that?


Could you be more specific here?

Thanks,
Christian
 
Could you be more specific here?

template <typename T>
ref class ReferenceWrapper
{
private:
initonly IList<T>^ list;
initonly int index;
public:
ReferenceWrapper(IList<T>^ list, int index) : list(list),
index(index) {}
ReferenceWrapper(const ReferenceWrapper% other) :
list(other.list), index(other.index) {}
operator T() { return list[index]; }
ReferenceWrapper operator=(const T% other) { list[index] =
other; return *this; }
};

// class ClrVector<T>.operator[]:
ReferenceWrapper<T> operator[] (size_t i) {
return ReferenceWrapper<T>(list, i);
}
 
Pavel said:
template <typename T>
ref class ReferenceWrapper

I think this could be a value class, it's so small.
{
private:
initonly IList<T>^ list;
initonly int index;
public:
ReferenceWrapper(IList<T>^ list, int index) : list(list),
index(index) {}
ReferenceWrapper(const ReferenceWrapper% other) :
list(other.list), index(other.index) {}
operator T() { return list[index]; }
ReferenceWrapper operator=(const T% other) { list[index] =
other; return *this; }

If this remains a ref class, maybe avoid the copy?

const-correctness is singularly useless in ref classes (apparently a
decision made early in the design of .NET, you can't do anything with a
reference-to-const), I'd recommend returning only the mutable wrapper class.
At any rate it ought to be inlined if you are only reading from it.

Sadly, you're also going to have to implement all the compound-assignment
operators and pre/post increment/decrement to get this to act right.
// class ClrVector<T>.operator[]:
ReferenceWrapper<T> operator[] (size_t i) {
return ReferenceWrapper<T>(list, i);
}
 
I think this could be a value class, it's so small.

Unfortunately, it is not possible, because one cannot override
operator= for a value class, which is what is needed here.

It could be a plain native struct, using gcroot<IList<T>> to point to
the list, but I'm not sure about performance implications of that. If
someone could clarify, it would be a useful bit of information.
If this remains a ref class, maybe avoid the copy?

How? Since it's an adapter for (I assume) some STLish C++ code, it
would expect to get an object with operator= that it will call, not a
handle to such object.
 
Pavel said:
Unfortunately, it is not possible, because one cannot override
operator= for a value class, which is what is needed here.

Ah, yes.
It could be a plain native struct, using gcroot<IList<T>> to point to
the list, but I'm not sure about performance implications of that. If
someone could clarify, it would be a useful bit of information.

I dunno either. I think there's potential for performance benefit by
raising IList`1 to a template parameter as well, callers could instantiate
using IList as the actual template argument when they need flexibility or
pass a specific class to enable a lot more inlining.
How? Since it's an adapter for (I assume) some STLish C++ code, it
would expect to get an object with operator= that it will call, not a
handle to such object.

I meant this copy ("return *this;" with stack semantics), when you could
return by tracking reference.
 
I dunno either.  I think there's potential for performance benefit by
raising IList`1 to a template parameter as well, callers could instantiate
using IList as the actual template argument when they need flexibility or
pass a specific class to enable a lot more inlining.

Yes, though in the .NET context, it will probably be a drop in the
ocean anyway.
I meant this copy ("return *this;" with stack semantics), when you could
return by tracking reference.

Ah, I was not aware that you could actually do that - but it does
indeed work fine, and is certainly the way to go; thanks for the hint.
 
Back
Top