Tom
Tom

Reputation: 3044

How to create a function which accepts variable number of variable arguments?

It is possible to create a function which accepts variable number of arguments:

function f(const x: array of const): String;

and use it this way:

f([1,3,4, "hello"]);

It is also possible to define an argument as "changeable":

function g(var x: Byte): String;

var B: Byte;
g(B);

But is it possible to define a function which can take any number of arguments of whatver type and change all of their values? I know I can do this using pointers but then I don't know the type of the parameter passed so it is quite unsafe to mess with them.


I just want to create a function which can return variable number of variables of many different types, not just of 1 type or just 1 variable. And I don't want to write zillions of lines to use the function- it should just be the function itself, no SetLength() before the function call or anything. So here is the best thing I made so far:

type TVarArr = Array of Variant;
     PVarArr = ^TVarArr;
Procedure f(a: PVarArr);
var
 i:Integer;
begin
  SetLength(A^, 4);
  a^[0] := 46;
end;

ar: TVarArr;
begin
f(@ar);
caption := IntToStr(ar[0]);

Upvotes: 0

Views: 2588

Answers (2)

Marjan Venema
Marjan Venema

Reputation: 19356

Tom will not be able to use this answer as his Delphi version isn't high enough, but anybody on D2010 or higher will be able to put the extended rtti's TValue to good use on this type of challenge.

Following is a small console app showing how to:

  • create a dynamic array of TValue's from a open array parameter;
  • copy a dynamic array of TValue's to a new dynamic array modifying individual values on the way;
  • modify the items in a dynamic array of TValues "in place".

Enjoy.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Rtti,
  System.SysUtils,
  System.TypInfo;

const
  StringKinds: set of TTypeKind = [tkChar, tkString, tkWChar, tkLString, tkWString, tkUString];

type
  TValueArray = array of TValue;

function ValueArrayFromConstArray(const aSource: array of TValue): TValueArray;
var
  idx: Integer;
begin
  SetLength(Result, Length(aSource));
  for idx := Low(aSource) to High(aSource) do
    Result[idx] := aSource[idx];
end;

function ReturnNewArray(const aSource: TValueArray): TValueArray;
var
  idx: Integer;
begin
  SetLength(Result, Length(aSource));
  for idx := Low(aSource) to High(aSource) do
    if aSource[idx].Kind in StringKinds then
      Result[idx] := 'Dest' + aSource[idx].ToString
    else
      if aSource[idx].Kind in [tkInteger] then
        Result[idx] := 10 + aSource[idx].AsInteger
      else
        Result[idx] := aSource[idx];
end;

procedure ModifyArrayValues(var aArray: TValueArray);
var
  idx: Integer;
begin
  for idx := Low(aArray) to High(aArray) do
    if aArray[idx].Kind in StringKinds then
      aArray[idx] := 'Dest' + aArray[idx].ToString
    else
      if aArray[idx].Kind in [tkInteger] then
        aArray[idx] := 10 + aArray[idx].AsInteger
      else
        ;//aArray[idx] := aArray[idx];
end;

var
  Source: TValueArray;
  Destination: TValueArray;
  Item: TValue;
  idx: Integer;
begin
  Source := ValueArrayFromConstArray(['Some', 42, TObject]);
  Destination := ReturnNewArray(Source);
  idx := 0;
  WriteLn('', #9, 'Old', #9, 'New');
  WriteLn('-', #9, '----', #9, '----');
  for Item in Source do
  begin
    WriteLn(idx, #9, Item.ToString, #9, Destination[idx].ToString);
    Inc(idx);
  end;
  WriteLn;
  WriteLn;
  WriteLn('', #9, 'Modified');
  WriteLn('-', #9, '----');
  Source := ValueArrayFromConstArray(['first', 50, TValue.From<TFloatValue>(fvCurrency)]);
  ModifyArrayValues(Source);
  for Item in Source do
  begin
    WriteLn(idx, #9, Item.ToString);
  end;
  ReadLn;
end.

Upvotes: 1

bummi
bummi

Reputation: 27384

Procedure All(var a:Array of Variant);
var
 i:Integer;
begin
  for I := Low(a) to High(a) do
      begin

        if VarType(a[i])=258  then
          a[i] := a[i] + ' modified';

      end;
end;

Procedure AllConst( a:Array of Variant);
var
 i:Integer;
begin
  for I := Low(a) to High(a) do
      begin
        Showmessage(a[i]);
      end;
end;


procedure TForm3.Button1Click(Sender: TObject);
var
 a:Array of Variant;
begin
  AllConst([1,2,'Test']);
  SetLength(a,3);
  a[0] := 3.141;
  a[1] := 'Test';
  a[2] := 27;
  all(a);
  Showmessage(a[1]);
end;

Upvotes: 1

Related Questions