Getting a range over a const Container
Francisco Soulignac
fsoulign at dc.uba.ar
Wed Jul 18 21:39:26 PDT 2012
Hi all,
it's been a while since this question, and I don't know how to solve
it either. The following code passes all the test using the last
version of dmd (2.059).
import std.container, std.algorithm;
//non const case
void assertequal(T)(SList!(T) l, int[] r) {
assert(equal(l[], r));
}
//const case
void const_assertequal(T)(const SList!(T) l, int[] r) {
assert(equal(l[], r));
}
unittest{
SList!(int) l;
l.insertFront(2);
l.insertFront(1);
assertequal (l, [1,2]);
assert(!__traits(compiles, const_assertequal(l, [1,2])));
}
The conflict with the last assertion is that opSplice can't be
applied to const. So, I looked at the container module, and made a
minimal example of a list myself (emulating SList).
struct List {
struct Node {
Node* next;
int val;
}
private Node* first;
struct Range {
//sorry about "actual", it should have been current
private Node* actual;
this(Node* first) {actual = first;}
@property front() {return actual.val;}
@property empty() const {return !actual;}
void popFront() {assert(!empty); actual = actual.next;}
Range save() {return this;}
}
unittest{static assert(isForwardRange!(Range));}
void add(int v) {
Node * next = first;
first = new Node;
first.val = v;
first.next = next;
}
Range opSlice() {
return Range(first);
}
}
void assertequal(L : List)(L l, int[] r) {
assert(equal(l[], r));
}
void assertequal_const(L : List)(L l, int[] r) {
assert(equal(l[], r));
}
unittest{
List l;
l.add(2);
l.add(1);
assert(equal(l[], [1,2]));
assertequal (l, [1,2]);
assert(!__traits(compiles, const_assertequal(l, [1,2])));
}
As far as I know, the problem comes with the transitivity of const.
In assertequal_const, l.first has type const(Node*), thus it can't
be converted to Node* in Range's constructor. I can't manage to
find a workaround here, because l.first will always have type
const(Node*), but for traversing the list I require to copy l.first
into some node, say actual, whose type is Node* so that I can move
it doing actual = actual.next. I would be happy to do
actual = cast(Node*)(l.first)
actual = actual.next;
but that code is suppose to be undefined, isn't it?
(http://dlang.org/const3.html : Removing Immutable With A Cast).
So, my question is how can I (correctly) traverse a const SList,
const DList, etc?
Best,
Francisco.
PS: sorry for the long mail.
More information about the Digitalmars-d-learn
mailing list