如何在自定义函数中使用 C++ Builder OPENARRAY

How to use C++ Builder OPENARRAY in a custom function

我想使用 OPENARRAY(或替代方法,如果有的话)将多个占位符变量传递到我的函数中。我知道它可以这样用于 String::Format

UnicodeString Text1 = "abc";
int Num2 = 1;
String::Format("Some %s and %d", OPENARRAY(TVarRec, (Text1, Num2));

我想像这样使用 Text1 和 Text2 变量:

MyFunction("Some %Txt1 and %Num2", OPENARRAY(TVarRec, ("%Txt1", Text1, "%Num2", Num2));

或者也许:

MyFunction(OPENARRAY(TVarRec, ("Some %Txt1 and %Num2", "%Txt1", Text1, "%Num2", Num2));

因此它会接受文本并将占位符变量替换为适当的变量内容。

我不知道如何从 MyFunction 中读取 OPENARRAY 参数内容。

所以函数看起来像:

UnicodeString MyFunction(UnicodeString Txt, ?WHAT-HERE?)
{
// read openarray here and replace vars
return StringReplace(Txt, ?WHAT-HERE?);
}

所以我不知道如何接受 OPENARRAY 变量。此外,如果您有以类似方式传递占位符、变量的替代解决方案(不使用 C++11),那也将受到欢迎。

当将 Delphi 风格的开放数组传递给函数时,实际上传递了两件事:

  • 指向数组第一个元素的指针

  • 数组最后一个元素的索引(不是数组的长度,如您所料!)。

因此,在您的示例中,您可以这样声明您的函数:

UnicodeString MyFunction(UnicodeString Txt, const TVarRec *Values, const int Values_High)

然后使用普通指针算法遍历数组。

TVarRec 可以保存多种不同的数据类型,因此您必须查看其 VType 字段以了解其实际引用的数据类型,然后访问相应的数据字段。一些值(整数和单个字符)直接存储在 TVarRec 本身中,而其他值(字符串和其他 class 类型)则由指针引用。

例如:

UnicodeString MyFunction(UnicodeString Txt, const TVarRec *Values, const int Values_High)
{
    if (((Values_High + 1) % 2) != 0)
        throw Exception("uneven number of values!");

    for (int index = 0; index <= Values_High; index += 2)
    {
        String OldValue, NewValue;

        switch (Values[index].VType)
        {
            case vtString:
                OldValue = * static_cast<const ShortString*>(Values[index].VString);
                break;

            case vtPChar:
                OldValue = Values[index].VPChar;
                break;

            case vtPWideChar:
                OldValue = Values[index].VPWideChar;
                break;

            case vtAnsiString:
                OldValue = * static_cast<const AnsiString*>(Values[index].VAnsiString);
                break;

            case vtWideString:
                OldValue = * static_cast<const WideString*>(Values[index].VWideString);
                break;

            case vtUnicodeString:
                OldValue = * static_cast<const UnicodeString*>(Values[index].VUnicodeString);
                break;

            default:
                throw Exception("illegal value type at index %d!", ARRAYOFCONST(( index )) );
        }

        switch (Values[index+1].VType)
        {
            case vtInteger:
                NewValue = Values[index+1].VInteger;
                break;

            case vtBoolean:
                NewValue = Values[index+1].VBoolean;
                break;

            case vtChar:
                NewValue = Values[index+1].VChar;
                break;

            case vtExtended:
                NewValue = * static_cast<const Extended*>(Values[index+1].VExtended);
                break;

            case vtString:
                NewValue = * static_cast<const ShortString*>(Values[index+1].VString);
                break;

            case vtPChar:
                NewValue = Values[index+1].VPChar;
                break;

            case vtWideChar:
                NewValue = Values[index+1].VWideChar;
                break;

            case vtPWideChar:
                NewValue = Values[index+1].VPWideChar;
                break;

            case vtAnsiString:
                NewValue = * static_cast<const AnsiString*>(Values[index+1].VAnsiString);
                break;

            case vtCurrency:
                NewValue = * static_cast<const Currency*>(Values[index+1].VCurrency);
                break;

            case vtVariant:
                NewValue = * static_cast<const Variant*>(Values[index+1].VVariant);
                break;

            case vtWideString:
                NewValue = * static_cast<const WideString*>(Values[index+1].VWideString);
                break;

            case vtInt64:
                NewValue = * static_cast<const __int64*>(Values[index+1].VInt64);
                break;

            case vtUnicodeString:
                NewValue = * static_cast<const UnicodeString*>(Values[index+1].VUnicodeString);
                break;

            default:
                throw Exception("illegal value type at index %d!", ARRAYOFCONST(( index )) );
        }

        Txt = StringReplace(Txt, OldValue, NewValue, TReplaceFlags() << rfReplaceAll);
    }

    return Txt;
}

MyFunction("Some %Txt1 and %Num2", OPENARRAY(TVarRec, ("%Txt1", Text1, "%Num2", Num2)) );

附带说明一下,当一个函数接受一个 TVarRec 值的开放数组时,您应该使用 ARRAYOFCONST() 宏而不是直接使用 OPENARRAY() 宏,例如:

String::Format("Some %s and %d", ARRAYOFCONST(( Text1, Num2 )) );

MyFunction("Some %Txt1 and %Num2", ARRAYOFCONST(( "%Txt1", Text1, "%Num2", Num2 )) );