Annoying transitivity-constant problem in D

I am facing a very annoying problem regarding transitive const in D.

I have the code below:

struct Slice(T) { T items; size_t start, length, stride; this(T items, size_t start = 0, size_t length = size_t.max, size_t stride=1) { if (length == size_t.max) { length = 1 + (items.length - start - 1) / stride; } this.items = items; this.start = start; this.length = length; this.stride = stride; } Slice!(T) opSlice(size_t a, size_t b) { // Everything is fine here return Slice!(T)(items, start + a * stride, b - a, stride); } const(Slice!(T)) opSlice(size_t a, size_t b) const { // ERROR! 'items' is const(T), not T. return const(Slice!(T))(items, start + a * stride, b - a, stride); } } 

The problem I ran into is that basically the data types const(Slice!int) and Slice!const(int) and const(Slice!const(int)) are just ... weird.

How to overload opSlice above to return a permanent copy of the current fragment , which can later be used as the original fragment ?

In other words, let's say I have:

 void test(in Slice!(int[]) some_slice) { //... } void main() { auto my_slice = Slice!(int[])(); const my_const_slice = my_slice; test(my_slice); // succeeds test(my_const_slice); //succeeds test(my_const_slice[0 .. 1]); // fails } 

The code above does not work. What is the best way to make it work? (I could, of course, always templatize test() , but then all slice variations - const(Slice!(Slice!const(int[]))) and such - will grow exponentially and vaguely.)

Edit:

Is there a solution that works for struct and class es?

+6
source share
2 answers

inout also works if Slice is a class:

 class Slice(T) { T items; size_t start, length, stride; this(){} inout this(inout T items, size_t start = 0, size_t length = size_t.max, size_t stride=1) { if (length == size_t.max) { length = 1 + (items.length - start - 1) / stride; } this.items = items; this.start = start; this.length = length; this.stride = stride; } inout(Slice!(T)) opSlice(size_t a, size_t b) inout{ return new inout(Slice!T)(items, start + a * stride, b - a, stride); } } void test(in Slice!(int[]) some_slice) { //... } void main() { auto my_slice = new Slice!(int[])(); const my_const_slice = my_slice; test(my_slice); // succeeds test(my_const_slice);//succeeds test(my_const_slice[0 .. 1]); // succeeds } 
+3
source

change the constructor to

 inout this(inout T items, size_t start = 0, size_t length = size_t.max, size_t stride=1) { if (length == size_t.max) { length = 1 + (items.length - start - 1) / stride; } this.items = items; this.start = start; this.length = length; this.stride = stride; } 

the inout keyword was created for this, it allows the constant / immutability of the parameter to apply to the result

+5
source

Source: https://habr.com/ru/post/900395/


All Articles