Раздражающая проблема транзитивно-константности в D - PullRequest
6 голосов
/ 31 октября 2011

Я сталкиваюсь с очень раздражающей проблемой, связанной с переходным константой в 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[]))) и т. Д. - вырастут в геометрической прогрессии, а то и в замешательстве).

Edit:

Есть ли решение, которое работает для struct s и class es?

Ответы [ 2 ]

5 голосов
/ 31 октября 2011

изменить конструктор на

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

3 голосов
/ 02 декабря 2011

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
}
...