Раздражающая, транзитивно-постоянная проблема в D
Я сталкиваюсь с очень раздражающей проблемой, касающейся транзитивного const в D.
У меня есть код ниже:
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);
}
}
Проблема, к которой я прибегаю, заключается в том, что в значительной степени типы данных const(Slice!int)
и Slice!const(int)
и const(Slice!const(int))
справедливы... странно .
Как я перегружаю opSlice
выше, чтобы вернуть постоянную копию текущего среза , которая впоследствии может быть использована как исходный срез ?
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
}
Код выше не работает. Каков лучший способ заставить его работать? (Я, конечно, всегда мог бы шаблонизировать test()
, но тогда все вариации среза - const(Slice!(Slice!const(int[])))
и так далее-будут расти экспоненциально и запутанно.)
Правка:
Есть ли решение, которое работает для struct
s и class
Эс?
2 ответа:
Inout также работает, если Slice является классом:
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 }
Измените конструктор на
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
для этого было сделано ключевое слово, которое позволяет постоянству / неизменности параметра распространяться на результат