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!
|