Раздражающая, транзитивно-постоянная проблема в 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[]))) и так далее-будут расти экспоненциально и запутанно.)

Правка:

Есть ли решение, которое работает для structs и classЭс?

2 6
d2

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 для этого было сделано ключевое слово, которое позволяет постоянству / неизменности параметра распространяться на результат