3

我在 Ubuntu 13.04 64 位上使用 DMD64 D Compiler v2.063.2。

我写了一个类如下:

class FixedList(T){
    // list
    private T[] list;

    // number of items
    private size_t numberOfItems;

    // capacity
    private size_t capacity;

    // mutex
    private Mutex listMutex;

    // get capacity
    @property public size_t Capacity(){ return capacity; }
    @property public shared size_t Capacity(){ return capacity; }

    // constructor
    public this( size_t capacity ){
        // initialise
        numberOfItems = 0;
        this.capacity = capacity;

        writeln("Cons Normal");
    }

    // constructor
    public shared this( size_t capacity ){
        // initialise
        numberOfItems = 0;
        this.capacity = capacity;

        // create mutex
        listMutex = cast(shared)(new Mutex());

        writeln("Cons Shared");
    }
}

虽然以这种方式编写类,但在 main 函数中,我编写了该代码:

auto list1 = new shared FixedList!int( 128 );
auto list2 = new FixedList!int( 128 );

用这个输出,完全没有错误,输出如下:

Cons Shared
Cons Normal

我接下来要做的是writeln从代码中删除这两行,当我重新编译代码时,它开始显示如下错误消息:

src/webapp.d(61): Error: constructor lists.FixedList!(int).FixedList.this called with argument types:
    ((int) shared)
matches both:
    lists.d(28): lists.FixedList!(int).FixedList.this(ulong capacity)
and:
    lists.d(37): lists.FixedList!(int).FixedList.this(ulong capacity)
src/app.d(61): Error: no constructor for FixedList
src/app.d(62): Error: constructor lists.FixedList!(int).FixedList.this called with argument types:
    ((int))
matches both:
    lists.d(28): lists.FixedList!(int).FixedList.this(ulong capacity)
and:
    lists.d(37): lists.FixedList!(int).FixedList.this(ulong capacity)
src/app.d(62): Error: no constructor for FixedList
make: *** [all] Error 1

基本上writeln功能是防止错误。实际上writeln在很多地方都在预防,我不确定为什么会这样。

我什至尝试用m3232 位标志编译代码,但它仍然相同。我做错了什么,还是这是一个错误?

4

2 回答 2

3

pure, nothrow, 和@safe被推断为模板函数。由于FixedList是模板化的,它的构造函数是模板化的。writeln不像(也不可能)pure像 I/O 那样。因此,虽然writelnis 在构造函数中,但它们被推断为 not pure,但构造函数所做的其他一切都是pure,因此如果没有对 的调用writeln,它们就会变为pure

在某些情况下,编译器能够更改pure函数的返回类型以将其隐式转换为immutableor shared。这是可行的,因为在这些情况下,编译器知道返回的是一个新的、唯一的对象,并且将其转换为immutableshared不会违反类型系统。并非所有pure函数都符合条件,因为参数类型会影响编译器是否可以保证返回值是唯一的,但许多pure函数能够利用这一点并将其返回值隐式转换为immutableor shared。这很有用,因为它可以避免代码重复(针对不同的返回类型)或复制 - 因为如果返回的类型与您需要的immutableshared,并且你不能保证它没有在其他地方被引用,你必须复制它以获得你想要的类型。在这种情况下,编译器能够保证该对象不会在其他地方被引用,因此它可以安全地为您转换它。

构造函数有效地返回新值,因此它们可能会受到此功能的影响。这样一来,如果构造函数是pure,您通常可以从中构造immutableshared取值,而不必复制构造函数(如果不是,则必须这样做pure)。与其他pure函数一样,这是否有效取决于构造函数的参数类型,但这通常是可能的,并且有助于避免代码重复。

导致您出现问题的原因是,当FixedList' 的构造函数都为时pure,编译器能够使用它们中的任何一个来构造shared对象。所以,它不知道选择哪一个,并给你一个模棱两可的错误。

我已将此报告为理论上的错误,即编译器可能应该更喜欢明确标记为的构造函数shared,但编译器开发人员将决定什么,我不知道。从函数隐式转换返回值的能力pure是一个相当新的功能,我们何时可以和不能进行这些隐式转换仍在探索中,这可能会导致意想不到的问题(可能是这样的问题)以及编译器错误(例如,至少有一种情况immutable,它当前不应该进行转换)。我相信这些问题会很快得到解决。

于 2013-07-16T20:16:55.083 回答
2

pure构造函数可以构建对象shared而无需对其自身进行标记shared

显然,纯粹是为构造函数推断的。

writeln不是pure。因此,有了它,构造函数就不是pure.

删除时writeln,构造函数变为pure. 两个构造函数现在都匹配shared调用。

于 2013-07-16T11:33:35.950 回答