为什么我不能在D中为结构体实现默认构造函数?

时间:2013-05-20 11:14:35

标签: d default-constructor

编写像

这样的代码
struct S
{
    this() // compile-time error
    {
    }
}

给我一​​条错误信息

default constructor for structs only allowed with @disable and no body.

为什么?

2 个答案:

答案 0 :(得分:13)

这是一个比人们最初期望的更棘手的案例。

D对C ++的一个重要且有用的功能是每个类型(包括所有用户类型)都有一些初始的非垃圾值,可以在编译时进行评估。它用作T.init,有两个重要的用例:

  1. 模板约束可以使用T.init值来检查是否可以在给定类型上执行某些操作(引用Kenji Hara的代码段):

    template isSomething(T) {
       enum isSomething = is(typeof({
           //T t1;                      // not good if T is nested struct, or has @disable this()
           //T t2 = void; auto x = t2;  // not good if T is non-mutable type
           T t = T.init;                // avoid default construct check
           ...use t...
       }));
    }
    
  2. 除非明确使用int i = void语法,否则始终会正确初始化变量。没有可能的垃圾。

  3. 鉴于此,出现了一个棘手的问题。我们应该保证T()和T.init是相同的(来自C ++的许多程序员会期望)或允许默认构造可能很容易破坏该保证。据我所知,尽管令人惊讶,但第一种方法的决定更安全。

    然而,讨论不断提出各种改进(例如,允许CTFE能够使用默认构造函数)。最近出现了一个such thread

答案 1 :(得分:9)

它源于D中的所有类型必须具有默认值的事实。有很多地方使用类型的init值,包括默认初始化成员变量和默认初始化数组中的每个值,并且init需要在编译了一些这样的案例。让init提供了很多好处,但它确实妨碍了使用默认构造函数。

真正的默认构造函数需要在所有使用init的地方使用(或者它不是默认值),但允许任意代码在{{}}的许多情况下运行{使用{1}}充其量只会有问题。至少,您可能被迫使其成为CTFE,并且可能init。一旦你开始对它施加这样的限制,很快你也可以直接将所有成员变量初始化为你想要的(这是pure发生的事情),因为你不会获得了很多(如果有的话),这会使默认构造函数变得毫无用处。

有可能同时拥有init和默认构造函数,但随后会出现关于何时使用另一个构造函数的问题,并且默认构造函数不再是默认构造函数。更不用说,开发人员在使用init值以及何时使用默认构造函数时可能会变得非常困惑。

现在,我们能够init结构的@disable值(导致它自己的一组问题),在这种情况下,它会是在任何需要init的情况下使用该结构是非法的。因此,有可能有一个默认的构造函数,它可以在运行时运行任意代码,但具体的后果是什么,我不知道。但是,我确信在某些情况下,人们会希望拥有一个需要init的默认构造函数,因此无法工作,因为它已经是@disabled(声明类型的数组可能会是其中之一)。

因此,正如您所看到的那样,通过D对init所做的事情,它使得默认构造函数的整个问题比其他语言更加复杂和有问题。

获得类似于默认构造的正常方法是使用静态init。像

这样的东西
opCall

然后,只要您使用struct S { static S opCall() { //Create S with the values that you want and return it. } } - 例如

S()

然后调用静态auto s = S(); ,并获得在运行时创建的值。但是,opCall仍将用于之前的任何地方(包括S.init),静态S s;仅在明确使用opCall时使用。但是,如果你将它与S()(禁用@disable this()属性)结合起来,那么你得到的东西类似于我之前描述的那些我们可能拥有@disabled init的默认构造函数。< / p>

我们可能会或者可能不会最终将默认构造函数添加到该语言中,但是由于init和语言的工作原因而添加它们存在许多技术问题,而Walter Bright没有认为应该添加它们。因此,对于要添加到语言中的默认构造函数,有人必须提出一个非常引人注目的设计,以适当地解决所有问题(包括令人信服的Walter),我不希望这发生,但我们会见。