Delphi泛型嵌套类

14

我正在比较C++和Delphi,发现了一些棘手的问题。

这是非常简单的C++代码:

template<typename T>
class C {

 class D {
  T x;
 }

}

在这种情况下,我们有一个模板类(=通用类)C和嵌套类D也是一个模板类。如果Tdouble,那么D内部的x就是double类型。
我不能说这句话:
template<typename T>
class C {

 template<typename T>
 class D {
  T x;
 }

}

这是一个错误,因为我已经“在”C中了,再加上另一个T就会产生冲突。要解决这个错误,我应该使用不同的名称,比如U

template<typename T>
class C {

 template<typename U>
 class D {
  T x;
 }

}

在Delphi中,我可以这样写:
type
 TClassC<T> = class
  private

   type
    TClassD = class
     private 
      x: T;
    end;

 end;

如果 T 是一个整数,那么现在 x 也是一个整数,因为(从我在网上阅读的内容中了解到)TClassD 是整数。在Delphi中,这也是合法的:
type
 TClassC<T> = class
  private

   type
    TClassD<T> = class // <-- note the <T> repeated!!
     private 
      x: T;
    end;

 end;

现在怎么样?如果我能在中再次声明,这意味着如果没有,我将拥有一个非泛型的TClassD类。我的理解正确吗?

3
很容易让您检查此代码,但我预计如果此代码编译通过,则内部 T 类型参数将隐藏外部 T 类型参数。因此,这就像您为内部类型参数使用了不同的名称一样,例如 TClassC<T1>,然后是 TClassD<T2> - David Heffernan
换句话说,我的期望是 Delphi 代码与您的 C++ 版本完全一致,没有冲突的参数名称。但是 C++ 语言可以保护您免受名称冲突的影响。 - David Heffernan
在你的第一个C++示例中,D本身不是一个模板类,来自C的模板只是在作用域内,因此D可以使用它。在你的第二个C++示例中,有两个名为T的模板参数确实是命名冲突,因为C++不喜欢在同一作用域中重复标识符。Delphi泛型不同于C++模板(尽管它们使用类似的语法),在这个特定的示例中,Delphi比C++更加灵活。 - Remy Lebeau
谢谢David和Remy。另外,@RemyLebeau你所说的“更灵活”是指允许使用相同参数声明嵌套类型吗?在这种情况下,我期望两个类(就像在我的最后一个示例中)具有相同的类型! - Raffaele Rossi
@Raffaele:不用同样的参数(那样没用),只是使用相同的参数名称。正如David所说,这很可能隐藏了外部的T。如果是这样,我也会使用不同的名称。 - Rudy Velthuis
显示剩余2条评论
1个回答

12

考虑这个简单的程序:

type
  TClassC<T> = class
  private
    type
    TClassD<T> = class
    private
      x: T;
    end;
  end;

var
  obj: TClassC<Integer>.TClassD<string>;

begin
  obj := TClassC<Integer>.TClassD<string>.Create;
  obj.x := 42;
end.

这个程序编译通过,但会出现以下提示:

[dcc32 Hint]: H2509 标识符“T”与容器类型的类型参数发生冲突

这个赋值操作证明了 x 的类型来自于外部泛型参数而不是内部泛型参数。

我必须说这让我感到很惊讶,因为我原本期望相反的结果。我原本期望内部泛型参数会隐藏外部的泛型参数。事实上,就我目前所知,内部类型无法引用其泛型参数。

为了能够同时引用两个泛型参数,您需要为它们使用不同的名称。例如:

type
  TClassC<T1> = class
  private
    type
    TClassD<T2> = class
    private
      x: T2;
    end;
  end;

这是相应的C++模板代码所迫使你做的事情。

在我看来,Delphi语言允许你编译本答案顶部的代码是一个设计上的弱点。


1
这确实是非常意外的。 - Rudy Velthuis
1
这很令人惊讶。虽然它确实加强了提示和警告通常应该像错误一样处理的观念,即使在某些情况下编译器仍将继续运行。 - J...
3
我觉得这个提示非常令人惊讶。如果有什么东西最令人困惑的,那就是这个。开发人员已经足够意识到这个问题并提出了提示,但却止步于此。他们在想什么?既然意识到了这个问题,为什么决定将编译器保持原样,接受永远无法使用泛型参数的通用类呢? - David Heffernan
好的,这很棘手。我本来想为双向链表编写一个类,但我发现了这种奇怪的行为。 - Raffaele Rossi
确保你开启了编译提示,然后解决它们! - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接