E2251 Ambiguous overloaded call to '%s' Delphi error
While porting our legacy project from old Delphi version to new Delphi version like from Delphi 7 to Delphi XE5, we faced above error frequently as we have used StrPas / StrPos / StrLen / TextToFloat function calls. And we found several cases and several reasons for cause of this error. Here I will explain why we get this error and what is the solution of this error.
Some of following error we faced.
E2251 Ambiguous overloaded call to 'Pos'
E2251 Ambiguous overloaded call to 'StrPas'
E2251 Ambiguous overloaded call to 'StrLen'
E2251 Ambiguous overloaded call to 'TextToFloat'
Why we get this error and what is the solution?
Following are possible reasons of occurring this error in latest Delphi versions code.
Case 1
If more than one overloaded version of a function exists in a unit and we are passing wrong arguments to the function call then this error will show.
For example.
We have different versions of StrPas function in SysUtils.pas
function StrPas(const Str: PAnsiChar): AnsiString;
function StrPas(const Str: PWideChar): UnicodeString;
On above function versions, one version is having PAnsiChar as parameter and the other one is having PWideChar as parameter.
And I have written a function in Delphi 7 which works fine.
function GetActualString(S: string): string;
begin
Result := StrPas(@S);
end;
But when I compile the same function in Delphi XE5 version then I get “E2251 Ambiguous overloaded call to StrPas” error.
Here the error is because @S has type of Pointer and the compiler does not know which overload function to be called as per the parameter type (PAnsiChar or PWideChar).
Solution
So here the solution is to change the code @S as PChar(S). In Delphi XE5 change the function as follow.
function GetActualString(S: string): string;
begin
Result := StrPas(PChar(S));
end;
We can use PWideChar also now PChar is PWideShar. And for AnsiString we can use PAnsiChar.
Another Example of Pointer type
Here is another version of the same function where I am passing the parameter as Pointer type. It will also result the same error and also have same solution.
function GetActualString(S: Pointer): string;
begin
Result := StrPas(S);
end;
So here we can see, I have declared S parameter of type Pointer so on function call statement compiler cannot get which version to be called. So to fix this issue we can apply same solution.
Solution
function GetActualString(S: Pointer): string;
begin
Result := StrPas(PChar(S));
end;
Case 2
When we have the same function in two different units and we have added both unit to a unit’s uses part.
For Example
Sometime during upgrade a project to Delphi XE5 from Delphi 7, we get "Ambiguous overloaded call to 'StrLen'" error for function StrLen because in new Delphi versions StrLen is moved to Ansistrings.pas unit and for backup support it also exists in SysUtils.pas unit.
System.SysUtils.pas
function StrLen(const PAnsiChar): Cardinal;
System.AnsiStrings.pas
function StrLen(const PAnsiChar): Cardinal;
Here I have used StrLen function on button click.
uses
SysUtils, Ansistrings;
……
procedure TForm1.Button1Click(Sender: TObject);
var
S : AnsiString;
L : Integer;
begin
S := 'Hello world!';
L := StrLen(PAnsiChar(S));
end;
Here you can see we have used both Sysutils and Ansistrings units. On button click we are calling StrLen function and you will get the error saying “E2251 Ambiguous overloaded call error to 'StrLen'”. And as function StrLen exists in both SystUtils and Ansistrings so compiler cannot get which one to be called.
Solution
So here the solution is add the unit name with the function call statement like follow.
procedure TForm1.Button1Click(Sender: TObject);
var
S : AnsiString;
L : Integer;
begin
S := 'Hello world!';
L := Ansistrings.StrLen(PAnsiChar(S));
end;
Note that here I used Ansistrings instead of Sysutils because the SysUtils one is deprecated and produces a compiler warning: "Moved to the AnsiStrings unit".
Case 3
If we have used Array as parameter to a function and we are passing dynamic array as value then it that case compiler cannot find what type of value we are passing and it will result to the error.
For Example
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure ArrayTest(iArray : array of integer); overload;
procedure ArrayTest (oArray : array of TObject); overload;
end;
.......
procedure TForm1.FormCreate(Sender: TObject);
begin
ArrayTest ([10, 15]);
end;
So where in above example we can ArrayTest is an overloaded function. One version of function having integer array as parameter and other one is having Tobject array as parameter. So when we call the function with passing dynamic array like above function call then it will result error "E2251 Ambiguous overloaded call to ArrayTest”. Because here, compiler cannot get what type of data we are passing and which overloaded version function to be called.
Solution
So here the solution is, we have to declare a local variable either of integer type or Tobject type and then need to pass to the function call like follow.
procedure TForm1.FormCreate(Sender: TObject);
var
Tmp : array of integer;
begin
SetLength(Tmp, 2);
Tmp[0] := 10;
Tmp[1] := 15;
ArrayTest (Tmp);
end;
Some of following error we faced.
E2251 Ambiguous overloaded call to 'Pos'
E2251 Ambiguous overloaded call to 'StrPas'
E2251 Ambiguous overloaded call to 'StrLen'
E2251 Ambiguous overloaded call to 'TextToFloat'
Why we get this error and what is the solution?
Following are possible reasons of occurring this error in latest Delphi versions code.
Case 1
If more than one overloaded version of a function exists in a unit and we are passing wrong arguments to the function call then this error will show.
For example.
We have different versions of StrPas function in SysUtils.pas
function StrPas(const Str: PAnsiChar): AnsiString;
function StrPas(const Str: PWideChar): UnicodeString;
On above function versions, one version is having PAnsiChar as parameter and the other one is having PWideChar as parameter.
And I have written a function in Delphi 7 which works fine.
function GetActualString(S: string): string;
begin
Result := StrPas(@S);
end;
But when I compile the same function in Delphi XE5 version then I get “E2251 Ambiguous overloaded call to StrPas” error.
Here the error is because @S has type of Pointer and the compiler does not know which overload function to be called as per the parameter type (PAnsiChar or PWideChar).
Solution
So here the solution is to change the code @S as PChar(S). In Delphi XE5 change the function as follow.
function GetActualString(S: string): string;
begin
Result := StrPas(PChar(S));
end;
We can use PWideChar also now PChar is PWideShar. And for AnsiString we can use PAnsiChar.
Another Example of Pointer type
Here is another version of the same function where I am passing the parameter as Pointer type. It will also result the same error and also have same solution.
function GetActualString(S: Pointer): string;
begin
Result := StrPas(S);
end;
So here we can see, I have declared S parameter of type Pointer so on function call statement compiler cannot get which version to be called. So to fix this issue we can apply same solution.
Solution
function GetActualString(S: Pointer): string;
begin
Result := StrPas(PChar(S));
end;
Case 2
When we have the same function in two different units and we have added both unit to a unit’s uses part.
For Example
Sometime during upgrade a project to Delphi XE5 from Delphi 7, we get "Ambiguous overloaded call to 'StrLen'" error for function StrLen because in new Delphi versions StrLen is moved to Ansistrings.pas unit and for backup support it also exists in SysUtils.pas unit.
System.SysUtils.pas
function StrLen(const PAnsiChar): Cardinal;
System.AnsiStrings.pas
function StrLen(const PAnsiChar): Cardinal;
Here I have used StrLen function on button click.
uses
SysUtils, Ansistrings;
……
procedure TForm1.Button1Click(Sender: TObject);
var
S : AnsiString;
L : Integer;
begin
S := 'Hello world!';
L := StrLen(PAnsiChar(S));
end;
Here you can see we have used both Sysutils and Ansistrings units. On button click we are calling StrLen function and you will get the error saying “E2251 Ambiguous overloaded call error to 'StrLen'”. And as function StrLen exists in both SystUtils and Ansistrings so compiler cannot get which one to be called.
Solution
So here the solution is add the unit name with the function call statement like follow.
procedure TForm1.Button1Click(Sender: TObject);
var
S : AnsiString;
L : Integer;
begin
S := 'Hello world!';
L := Ansistrings.StrLen(PAnsiChar(S));
end;
Note that here I used Ansistrings instead of Sysutils because the SysUtils one is deprecated and produces a compiler warning: "Moved to the AnsiStrings unit".
Case 3
If we have used Array as parameter to a function and we are passing dynamic array as value then it that case compiler cannot find what type of value we are passing and it will result to the error.
For Example
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure ArrayTest(iArray : array of integer); overload;
procedure ArrayTest (oArray : array of TObject); overload;
end;
.......
procedure TForm1.FormCreate(Sender: TObject);
begin
ArrayTest ([10, 15]);
end;
So where in above example we can ArrayTest is an overloaded function. One version of function having integer array as parameter and other one is having Tobject array as parameter. So when we call the function with passing dynamic array like above function call then it will result error "E2251 Ambiguous overloaded call to ArrayTest”. Because here, compiler cannot get what type of data we are passing and which overloaded version function to be called.
Solution
So here the solution is, we have to declare a local variable either of integer type or Tobject type and then need to pass to the function call like follow.
procedure TForm1.FormCreate(Sender: TObject);
var
Tmp : array of integer;
begin
SetLength(Tmp, 2);
Tmp[0] := 10;
Tmp[1] := 15;
ArrayTest (Tmp);
end;
This: `function GetActualString(S: string): string;` doesn't make any sense. Just use `UniqueString()`. Or do `Result := PChar(s);`. `StrPas()` does nothing!
ReplyDeleteGetActualString function is just an example. If we have sued StrPas, StrPos, StrLen functions and written code like StrPas(@S) then we can replace with the solution. I agree that we don't use StrPas very frequently but we do use StrPos, StrLen. So that same solution can be applied for them too.
ReplyDelete