D中恼人的,传递性的问题

时间:2011-10-30 23:16:38

标签: const d

我遇到了关于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 个答案:

答案 0 :(得分:5)

将构造函数更改为

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关键字,它允许参数的const-ness / immutability传播到结果

答案 1 :(得分:3)

如果Slice是一个类,

inout也有效:

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
}