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

标签 c++ c++builder variadic-functions

我想使用 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 本身中,而其他值(字符串和其他类类型)则由指针引用。

例如:

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 )) );

关于c++ - 如何在自定义函数中使用 C++ Builder OPENARRAY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47695101/

相关文章:

c++ - 带多个参数的显式构造函数

c++ - OpenGL c++ - 出现不需要的黑色三角形

c++ - 公开 .lib 文件的功能

java - 在 Java 中强制用户填充 varargs 参数的好方法

java - Java API 中 Varargs 的源代码?

c++ - 如何将数据追加到已有数据的文件中

c++ - dynamic_cast 派生类型失败,为什么?

android - 使用蓝牙组件将数据从 Android 手机传输到串行设备时出现问题

c++ - 如何在 THeaderSection 中嵌入 VCL TEdit 控件?

assembly - stdcall (callee-pops) 中变量参数的堆栈清理