C++可否将变量列表作为一个整体传递给函数的参数列表

C++能否将变量列表作为一个整体传递给函数的参数列表?
就是假如有一个函数

void func(int a, int b, int c);

那么能否将

int arr[3];

通过某种技术手段作为函数func的参数传递、使得效果上等价于

func(a[0], a[1], a[2]);

?本质上就是用单个实参的版本来代替3个实参的版本,但又不是函数重载。

如果可以的话,怎么做呢?另外上面是所有参数同类型的情况;如果所有的参数类型不一样,又该怎么做呢?
------解决思路----------------------
不安全
编译器没有明确定义栈高低和内存高低的问题
比如压栈如果是往高地址走,约定是__cdcel
那你需要先反转a,才能和正确的顺序一样
------解决思路----------------------
数组的话,变长模板可以做到。

不同类型的话得你怎么存储的。
------解决思路----------------------
如果同种类型,那可以用数组指针啊,也可以用vector。不通类型的数据的话,那就定义一个struct
------解决思路----------------------
如果同种类型,那可以用数组指针啊,也可以用vector。不通类型的数据的话,那就定义一个struct
------解决思路----------------------
把你要传的数据封装在结构体里呢?
------解决思路----------------------
为什么有这种需求?

------解决思路----------------------
typedef struct {
a[3]
}Arr3;

typedef int (*pfun)(Arr3);
int fun(int a,int b,int c)
{
    return a+b+c;
}

int run(pfun pf,int a,int b,int c)
{
       Arr3 arr={a,b,c};
      return pf(arr);
}
这样做试试
因为压栈是反序的
所以,指针,int ,double,long long 等类型的数据,

如果是同一类型,在栈中相当于数组的存在。
数组不能按照全部数据压栈传递,
但是现在 struct  可以全部数据压栈。
 char,short,float 通常不可以这么做

------解决思路----------------------
template <int N>
void func(int (&arr)[N])
{
     // do something
}


int arr[3];
func(arr);


这样可以。

但是这样做有不好的地方,就是:如果你可以确定这个func函数处理的数组的长度在绝大多数情况下都是固定的,比如绝大多数情况下func处理的数组的长度都是3。如果处理的数组长度是不确定的,那么这样做就不好了,因为如果你调用了10次func,每次处理的数组长度都不同,那么模板在实例化时就会生成10次。这样代码的体积就变得很大了。


上面这种做法看起来似乎很炫,但其实没什么用。原因已经解释过了。

远远不如传递两个参数:一个是数组首地址、另一个是数组长度。

数组长度可以这样算:sizeof(arr) / sizeof(arr的类型)    很方便。


初学者往往希望能把数组作为一个整体传递给一个函数,这是一种错觉。

int、char等等这些属于简单的数据类型,而数组属于复合数据类型。复合的意思就是一个数组里包含着不止一个信息。所以自然在传递的时候,传递了不止一个信息。因此处理数组的函数的参数自然也不止一个。


如果实在需要只传递一个参数去处理数组,如楼上的朋友们所说,可以用struct把数组包起来,像这样:
struct arr{int * p; int size;}
p初始化成数组首地址,size是数组长度。然后传递结构体arr。
这样做要比最一开始的模板要好得多得多。


所以再强调一次:不要随便用模板来做这种事情!
------解决思路----------------------
引用:
Quote: 引用:


如果实在需要只传递一个参数去处理数组,如楼上的朋友们所说,可以用struct把数组包起来,像这样:
struct arr{int * p; int size;}
p初始化成数组首地址,size是数组长度。然后传递结构体arr。
这样做要比最一开始的模板要好得多得多。


所以再强调一次:不要随便用模板来做这种事情!


感谢仁兄以及楼上各位的解答。不过阁下可能误解了我的意思了,我并不是想要一次性传递一个数组。其实我这个问题和之前问的那个“在控制台中输入命令即执行对应函数”的问题是一脉相承的,如果在C++中确实可以做到的话,那么关键点就在这里:
比如说我解析出了命令
run: add 1 2 3 ... n
的函数名字是add,后面有n个int类型的参数。因为实现不知道n是多少,所以在代码中没法像这样写函数调用语句:
add(1,2,...,n);
所以,如果有办法只传递一个数组int arr[n]就可以调用这个需要n个int参数的函数add的话,那么我之前的那个问题就解决了。



我去看了你那个帖子了   我还是不明白你的问题所在:
如果在控制台内输入 add 1 2 回车,然后就调用add(1, 2)

这实现起来有难度吗?

反正格式就是:一个函数名 后面跟若干参数

所以:
if(输入的第一个部分和add相等)
      add(参数1, 参数2);


这不就行了?
------解决思路----------------------
引用:
template <int N>
void func(int (&arr)[N])
{
     // do something
}


int arr[3];
func(arr);


这样可以。

但是这样做有不好的地方,就是:如果你可以确定这个func函数处理的数组的长度在绝大多数情况下都是固定的,比如绝大多数情况下func处理的数组的长度都是3。如果处理的数组长度是不确定的,那么这样做就不好了,因为如果你调用了10次func,每次处理的数组长度都不同,那么模板在实例化时就会生成10次。这样代码的体积就变得很大了。


上面这种做法看起来似乎很炫,但其实没什么用。原因已经解释过了。

远远不如传递两个参数:一个是数组首地址、另一个是数组长度。

数组长度可以这样算:sizeof(arr) / sizeof(arr的类型)    很方便。


初学者往往希望能把数组作为一个整体传递给一个函数,这是一种错觉。

int、char等等这些属于简单的数据类型,而数组属于复合数据类型。复合的意思就是一个数组里包含着不止一个信息。所以自然在传递的时候,传递了不止一个信息。因此处理数组的函数的参数自然也不止一个。


如果实在需要只传递一个参数去处理数组,如楼上的朋友们所说,可以用struct把数组包起来,像这样:
struct arr{int * p; int size;}
p初始化成数组首地址,size是数组长度。然后传递结构体arr。
这样做要比最一开始的模板要好得多得多。


所以再强调一次:不要随便用模板来做这种事情!

猜内存布局不是一个好的习惯,没有移植性
------解决思路----------------------
引用:
Quote: 引用:


if(输入的第一个部分和add相等)
      add(参数1, 参数2);


这不就行了?

这个是硬编码,太不灵活了。要是提前不知道函数原型呢?要是可以调用的函数原型全靠用户指定呢?


这种活C++不擅长。还是弄脚本语言吧。
------解决思路----------------------
引用:
Quote: 引用:


if(输入的第一个部分和add相等)
      add(参数1, 参数2);


这不就行了?

这个是硬编码,太不灵活了。要是提前不知道函数原型呢?要是可以调用的函数原型全靠用户指定呢?



类似printf这种可变参数的函数?

那你就去查查可变参数的函数怎么玩    可变参数在每个c++版本里都有
------解决思路----------------------
引用:
Quote: 引用:


if(输入的第一个部分和add相等)
      add(参数1, 参数2);


这不就行了?

这个是硬编码,太不灵活了。要是提前不知道函数原型呢?要是可以调用的函数原型全靠用户指定呢?


你的用户是什么样的用户,他可以提供一个函数?还是他只能提供一个函数的名字,而函数本身是你已经写好的?

前者,你应该是提供了一个库。可以参考各种回调函数的写法。
一般可以用一个统一的 int func(void*) 或者 void* func(void*) 做接口,由用户自己去解释 void * 里面的东西。
同时你还得设计一种 “语言” 来描述 void * 里面的结构,以为这个参数貌似是要由你来准备的。

后者,没什么不灵活的,这样挺好。所有函数原型提前都是知道的。

=======================

"要是提前不知道函数原型呢?"
对于 C++ 来说,提前不知道函数原型是搞不定的。在编译的时候所有的函数原型都必须确定。
------解决思路----------------------
引用:
Quote: 引用:


你的用户是什么样的用户,他可以提供一个函数?还是他只能提供一个函数的名字,而函数本身是你已经写好的?

前者,你应该是提供了一个库。可以参考各种回调函数的写法。
一般可以用一个统一的 int func(void*) 或者 void* func(void*) 做接口,由用户自己去解释 void * 里面的东西。
同时你还得设计一种 “语言” 来描述 void * 里面的结构,以为这个参数貌似是要由你来准备的。

后者,没什么不灵活的,这样挺好。所有函数原型提前都是知道的。

=======================

"要是提前不知道函数原型呢?"
对于 C++ 来说,提前不知道函数原型是搞不定的。在编译的时候所有的函数原型都必须确定。


第一部分,应该是前者吧。第二个,这么说吧,说说完整的问题:
有一个类CCommand,它有两个方法:
void RegisterCommand(); (省去参数列表)

void AnalyzeCommand();  (也省去参数列表)
用户在使用这个类的时候,先在main函数中定义一些自己需要的函数,然后调用CCommand对象的RegisterCommand()方法来注册这些函数,然后在运行main函数的时候,在控制台输入一个指令
run: add 3 4
那么就会调用函数
add(3,4);
如果add(int, int)函数被注册了的话,就会产生相应的效果。

所以,因为你不知道用户在main函数中会注册哪些函数,所以你不能提前知道可能被调用的函数的参数列表。


如果用户真的是怎么搞都可以;
  那么解析参数这个事情你也做不了。你也得交给用户去搞。
  RegisterCommand(const char * name, void *(*func)(void *), void*(*parse)(const char *)); // 随便写一下

   然后匹配上 name 之后,调用 name 的 parse 来解析参数,解析的结果装在一个用户自己的随便什么类型的变量里,把指针传出来,再调用 func ,参数的解析的结果。

或者,把参数解析的结果存成这样的东西:
struct param_list {
   int n; // 数量
   struct param * p; // 参数表;
};

struct param {
   int type; // 类型
   union value v;
};

union value {
   int ival;
   char * sval;
  double dval;
  ....
};

所有的用户函数都用 func(struct param_list *)。