C#中params对象[]的C++替代方案

C++ alternative to params object[] in C#

本文关键字:C++ 方案 params 对象      更新时间:2023-10-16

大家好,我想用C++为C#编写一些代码,但由于C++中没有params对象,我需要一些帮助:p

好的,下面是我想做的:

static Int32 Procedure(UInt32 address, params Object[] parameters)
{
    Int32 length = parameters.Length;
    Int32 index = 0;
    UInt32 count = 0;
    UInt32 Strings = 0;
    UInt32 Single = 0;
    UInt32 Array = 0;
    while (index < length)
    {
        if (parameters[index] is Int32)
        {
            WriteInt32(0x10050000 + (count * 4), (Int32)parameters[index]);
            count++;
        }
        else if(paramaters[index] is String){ }.... // Thats just one thing i wanna    use.. i've got more
        ..........
        ..........
    }
return ReadInt32(0x000000);
}

所以我需要弄清楚参数的类型+我想使用未知数量的参数,我不知道我该如何做xD

我希望它很清楚,希望有人能帮助我:3天啊,尼科!

您可以使用可变模板在C++中实现类似的功能。请注意,由于C++没有运行时反射,因此不可能动态获取任何值的类型:只能在编译时进行重要的是,这也意味着不能在运行时构建参数列表并将其传递给函数,而不推出自己的东西。

它也可以说比C#等价物复杂得多(但话说回来,如果C++拥有C#的所有优点而没有缺点,那么就没有人会使用C#)。

可能还有其他模式,但我通常使用的模式看起来是这样的(例如打印功能):

template<typename... T>
void print_all_values(int value, T... values)
{
    printf("%i ", value);
    print_all_values(values...);
}
template<typename... T>
void print_all_values(double value, T... values)
{
    printf("%g ", value);
    print_all_values(values...);
}
template<typename... T>
void print_all_values(const char* value, T... values)
{
    printf("%s ", value);
    print_all_values(values...);
}
template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)
{
    printf("(can't print) ");
    print_all_values(values...);
}
void print_all_values() {}
print_all_values(4, "hello world", 5.2, nullptr);
// prints: "4 hello world 5.2 (can't print)"

这里发生了什么:

template<typename... T>
void print_all_values

这告诉编译器为它在程序中找到的每个不同的参数类型序列创建一个不同版本的print_all_values

void print_all_values(int value, T... values)
void print_all_values(double value, T... values)
void print_all_values(const char* value, T... values)

它们根据第一个参数区分调用。这里的想法是,函数只打印它的第一个参数,然后递归地调用带有剩余参数的模板版本:

{
    printf("%s ", value);
    print_all_values(values...);
}

在递归链的末尾,每个参数都已打印出来。

对于我的示例print_all_values(4, "hello world", 5.2, nullptr),基本上会发生以下情况:

  • print_all_values(4, "hello world", 5.2, nullptr)->编译器使用print_all_values(4, ...),在运行时执行printf("%i", value),函数末尾的调用变为:
  • print_all_values("hello world", 5.2, nullptr)->编译器使用print_all_values("hello world", ...),在运行时执行printf("%s", value),然后:
  • print_all_values(5.2, nullptr)->编译器使用print_all_values(5.2, ...)printf("%g", value),然后:
  • print_all_values(5.2, nullptr)->编译器找不到合适的重载,所以它返回到print_all_values(Unknown&& value, T... values)重载,执行"(无法打印)",并创建对print_all_values()的调用,但不执行任何操作

最后一次过载:

template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)

告诉编译器如何处理任何未知类型(在这种情况下,通过打印(can't print))。如果没有这个重载,如果我们试图打印未知类型,就会出现编译时错误(因为这一切都发生在编译时,请记住)。

您是否已经尝试过如下示例中给出的可变模板声明?

template<typename... Args>
static int32_t Procedure(uint32_t address, Args&&... parameters) {
    // ...
}

C++允许您以可变模板函数的形式编写接受任意数量参数的函数:

template<typename... ARGS>
void f( ARGS... args )
{
}

在该示例中,ARGSargs表示所谓的variadic packs。模板参数和函数参数都不是,只是表示一组模板参数和一组函数参数的东西(分别)

因此,它们不是参数,而是参数包,并且它们不能直接操作。若要使用可变数据包的内容,必须使用省略号展开数据包。考虑上面的例子:template<typename... ARGS>声明了一个带有名为ARGS的变量包的变量模板,该变量包表示一组类型模板参数
在下一行中,我们展开该包(ARGS...),将这些类型用作函数自变量的类型。从而生成函数自变量args的变分包。

要在函数中使用这些论证,还应该展开args。由于包只是一组不确定的论证,您只能在使用孔论证集的上下文中使用它,换句话说,您不能直接访问包的特定元素。例如:

template<typename... ARGS>
void f( ARGS... args )
{
    f( args... ); //We call f() expanding the args pack of function parameters
                  //and passing the set of parameters to the function.
}

如果你需要遍历包中的一组参数(你会在C#中使用params上的下标运算符),你必须使用模式匹配和头尾递归列表遍历的函数编程方式:

template<typename HEAD , typename... TAIL>
void print( const HEAD& head , const TAIL&... tail )
{
    std::cout << head << std::endl; //Do something with the head (Which is a 
                                    //normal function parameter)
    print( tail... ); //Pass the tail to the next call
}

请注意,函数至少需要一个参数(可变模板可以为空,但print()有一个非可变参数)。你应该提供一个没有参数的重载作为基本情况(当论证列表中没有更多论证时的情况):

void print()
{
    //Base case. Does nothing.
} 

现在考虑print()函数的签名:是一个可以接受任何类型组合的任何数量的参数的函数。与C#(And Java)方法不同,C#方法将参数存储在通用基类的数组中,并依赖多态性和强制转换),C++方法使用静态类型的替代方法,其中每个函数参数的类型在编译时都很好地确定。

相关文章: