7

私は現在、コンパイル エラーで立ち往生しています。私たちの会社の誰も助けることができません。悲しいことに、SO または Google の正しい検索パターンが見つかりません。

コードとして、継承された 2 つのインターフェイスと継承された 2 つのクラスを使用しています。次のコードは、エラーを再現します。

program Project22;

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

「TKeyObjectStorage」のコンパイラ エラーは次のとおりです。

[DCC エラー] Project22.dpr(11): E2514 型パラメーター 'T' はインターフェイス 'IStorageObject' をサポートする必要があります

私が思うに、コンパイラはクラス 'TKeyObjectStorage' のパラメータ T を正しく認識していません。必要なタイプ「IKeyStorageObject」には親タイプ IStorageObject があるため、正しいはずです。

なぜこれが機能しないのですか?私は何を間違っていますか?これは Delphi では不可能ですか?

4

1 に答える 1

9

アップデート

元の質問には、私が特定した問題がありました(以下を参照)。ただし、ここで説明する修正は XE3 以降では問題ありませんが、以下のプログラムは XE2 ではコンパイルできません。したがって、これは XE2 ジェネリック コンパイラのバグであると結論付けています。

とにかく、Delphi XE2の回避策は次のとおりです。

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

元の答え

コンパイラ エラーが発生した完全なプログラムを提供していただければ、よりよい結果が得られます。そのエラーを確認するには、オブジェクトをインスタンス化する必要があります。

しかし、私はあなたの問題を再現したと思います。したがって、問題は次のコードだと思います。

TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...

一般制約を と の両方に適用しTKeyますT。ここで、明らかに、制約を適用するTだけが必要なので、次のように記述する必要があります。

TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...

以下は、Delphi XE3の変更に従ってコンパイルされる短いプログラムです。

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

カンマをセミコロンに変えた微妙なニュアンスです。かなりの句読点によるプログラミングは決して楽しいものではありません。とはいえ、仮パラメーター リストのコンマとセミコロンの違いはよく知られているので、ここで同じ違いが示されてもそれほど驚くことではありません。

ドキュメントでは、次のことを考慮しています。

複数の型パラメータ

制約を指定するときは、パラメーター リスト宣言の場合と同様に、複数の型パラメーターをセミコロンで区切ります。

type
  TFoo<T: ISerializable; V: IComparable>

パラメーター宣言と同様に、複数の型パラメーターをコンマ リストでグループ化して、同じ制約にバインドできます。

type
  TFoo<S, U: ISerializable> ...

上記の例では、SUの両方がISerializable 制約にバインドされています。

于 2013-10-30T12:37:14.373 に答える