This topic describes some programming issues that you might encounter when dealing with generics, one of Delphi's newest features.
Delphi generics are exposed to C++ as templates. However, it's important to realize that the instantiations occur on the Delphi side, not in C++. Therefore, you can only use these template for types that were explicitly instantiated in Delphi code. For example, let's declare a simply generic, TList<T>, in Delphi:
interface type MyTList<T> = class(TList<T>) // TList is a class in the Generics.Collections namespace FItems: array of T; protected function GetLength: Integer; public function Get(Index: Integer): T; published property Len: Integer read GetLength; end; { ScoreList derived from a TList<double>} ScoreList = class(MyTList<double>) end; { StringList derived from a TList<string>} StringList = class(MyTList<string>) end; implementation {$R *.dfm} function MyTList<T>.GetLength: Integer; begin Result := Count; end; function MyTList<T>.Get(Index: Integer): T; begin Result := Items[Index]; end;
The interface above is exposed to C++ as the following:
// Template declaration generated by Delphi parameterized types is // used only for accessing Delphi variables and fields. // Don't instantiate with new type parameters in user code. template<typename T> class PASCALIMPLEMENTATION MyTList__1 : public Generics_collections::TList__1<T> { typedef Generics_collections::TList__1<T> inherited; private: typedef DynamicArray<T> _MyTList__1__1; public: _MyTList__1__1 FItems; protected: int __fastcall GetLength(void); public: T __fastcall Get(int Index); __published: __property int Len = {read=GetLength, nodefault}; public: /* TList<T>.Create */ inline __fastcall MyTList__1(void)/* overload */ : Generics_collections::TList__1<T>() { } /* TList<T>.Destroy */ inline __fastcall virtual ~MyTList__1(void) { } }; class DELPHICLASS ScoreList; class PASCALIMPLEMENTATION ScoreList : public MyTList__1<double> { typedef MyTList__1<double> inherited; public: /* TList<Double>.Create */ inline __fastcall ScoreList(void)/* overload */ : MyTList__1<double>() { } /* TList<Double>.Destroy */ inline __fastcall virtual ~ScoreList(void) { } }; class DELPHICLASS StringList; class PASCALIMPLEMENTATION StringList : public MyTList__1<System::UnicodeString> { typedef MyTList__1<System::UnicodeString> inherited; public: /* TList<string>.Create */ inline __fastcall StringList(void)/* overload */ : MyTList__1<System::UnicodeString>() { } /* TList<string>.Destroy */ inline __fastcall virtual ~StringList(void) { } };
C++ code linking with the .obj created from the above Delphi unit can use instances of TList__1<double> or ScoreList.
void UseScoreList() { ScoreList* list = new ScoreList(); list->Add(1.0); list->Add(2.0); int len = list->Len; assert(len == 2); delete list; } void UseTList__1() { // C++ code can use the Generics defined in Delphi directly // as long as the C++ code limits itself to types for which // the generic was instantiated on the Delphi size. For example, // since test.pas uses TList<String> and TList<double> we can use // these here. However, if we try to use TList__1>char> we'll get // an error since the Delphi side did not instantiate // TList<AnsiChar>. TList__1<double>* dblList = new MyTList__1<double>(); dblList—>Add(1.0); dblList—>Add(1.5); double d = dblList—>Get(1); delete dblList; MyTList__1<UnicodeString> *stringList = new MyTList__1<UnicodeString>(); stringList->Add("hiya"); stringList->Add("there"); stringList->Add("buckeroo"); UnicodeString dstring = stringList->Get(0); delete stringList; }
If C++ code attempts to use a Delphi generic for types that were not instantiated in Delphi, you'll get errors at link time. For example, the following code attempts to use TList__1<char> when the Delphi code did not explicitly instantiate TList<AnsiChar>:
void UseListOfChar() { TList__1<char>* charList = new TList__1<char>(); charList->Add('a'); char ch = charList->Get(1); delete charList; }
While the code above compiles, the following errors are generated at link time:
[ILINK32 Error] Error: Unresolved external 'Test::MyTList__1<char>::>::' referenced from USETEST.OBJ [ILINK32 Error] Error: Unresolved external '__fastcall Test::MyTList__1<char>>::Add(char)' referenced from USETEST.OBJ [ILINK32 Error] Error: Unresolved external '__fastcall Test::MyTList__1<char>::Get(int)' referenced from USETEST.OBJ
To eliminate the error, you have to make sure that the Delphi code uses the type MyTList<AnsiChar>.
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
|
What do you think about this topic? Send feedback!
|