您好 我有一个带有成员函数的类,它接受可变数量的参数。该类知道在实例化后期望的参数数量。 e.g
class myClass
{
myClass(int num_args){na=num_args;};
private:
int na;
public:
void do_something(int num_args, ...);
}
void myClass::do_something(int num_args, ...)
{
va_list vl;
va_start(vl, num_args);
for(int i=0; i < num_args; i++)
do_anotherthing(va_arg(vl, type));
va_end
}
所以我最终打电话如下:
myClass A(5);
myClass B(4);
A.do_something(5, a, b, c, d, e);
B.do_something(4, a, b, c, d);
我必须继续指定我传递的参数数量似乎不整洁。什么是最好的解决方法?我考虑过重载一堆函数,每个函数都有n个参数,一个宏可以为我设置num_args。但理想情况下,我希望能够将do_something定义为
void do_something(...);
以某种方式获取stdargs的东西来处理类的num_args而不是传入的值。
非常感谢你的想法。
答案 0 :(得分:2)
请不要那样做。可变数量的参数在C ++中非常罕见
实现所需目标的最佳方法是创建一个int列表并将该列表作为参数传递
你可以检查函数内的列表大小
答案 1 :(得分:1)
我不明白为什么你不能在你的功能中使用na
,即
void myClass::do_something(int num_args, ...)
{
va_list vl;
va_start(vl, na);
for(int i=0; i < na; i++)
do_anotherthing(va_arg(vl, type));
va_end
}
但是,type
是什么? do_anotherthing
期待什么类型?
不幸的是,可变方法不是类型安全的,如果va_arg
不是您指定的类型,则vl
是否会生成错误尚不清楚。考虑改为做boost::format
之类的事情,即
A % a % b % c % d % e;
operator%
对所提供的每个元素执行do_anotherthing
,直到达到最大数量。
编辑:经过进一步考虑,最好是do_something
返回一个帮助它完成所有操作的辅助对象,例如
do_something_helper myClass::do_something() {
return do_something_helper( na ); }
struct do_something_helper {
int count;
do_something_helper( int c ) : count( c ) {}
template< class T >
do_something_helper& operator%( T val ) {
--count;
if ( count < 0 ) {
//trigger some error condition
}
do_anotherthing( val );
return *this;
}
~do_something_helper() {
if ( count > 0 ) { // too few args
//trigger some error condition
}
}
}
将具有使用
A.do_something() % a % b % c % d % e;
答案 2 :(得分:1)
您可以使用operator<<
之类的C ++标准流,而不是使用varargs吗?然后它是所有类型安全的,你不必担心你用varargs注意到的问题。
答案 3 :(得分:0)
解决这个问题的最佳方法是什么?
您可以考虑使用sentinel值,这样您就不必计算元素 - 它更少(但仍然)容易出错。从使用安全的角度来看,重载可能更好,但如果参数的数量通常很大且不可预测,那么显然它变得不切实际。
更好的是,传入vector
或数组。对于数组,您可以让被调用的函数知道大小ala:
template <size_t N>
void f(type (&x)[N])
{
...
}
您的示例表明type
是常量且在编译时已知,因此vector
或数组应该足够。如果这是一个简化,请考虑vector
或boost variant
或any
数组,或者可能是tuple
,或者可能是一个返回对象引用的函数,你可以链接调用提供连续的值(许多运算符都这样做)。
答案 4 :(得分:0)
谢谢大家。 我不担心类是安全的类,它是一个非常小的代码,只能在严格控制的条件下使用。 我不想使用运算符(&lt;&lt;例如),因为我想要一个函数调用来获取所有参数。设置向量并传递它同样如此,我想在一次调用中完成所有操作(args总是字符串)。 我将继续指定参数的数量,或创建一个宏(叹气)。
答案 5 :(得分:0)
我知道这不是一个好习惯,并且有更好的解决方案来解决这个问题,但正如省略号参数的练习一样,我发现这是一个很好的练习。
此代码适用于我的编译器(VS2013),我很抱歉我必须使用内联汇编,但由于堆栈组织,首先想法使用本地堆栈变量无法工作。 所以这就是:
#include <iostream>
#include <cstdarg>
#include <stdint.h>
using namespace std;
double avg(double * sp, ...);
#define AVERAGE(n, ...) \
{ \
int * stackP; \
__asm { \
__asm mov ebx, esp \
__asm mov stackP, ebx \
} \
double a = avg(stackP, n, __VA_ARGS__); \
cout << "Average is: " << a << endl; \
}
template <typename T>
double avg(int * sp, T n, ...)
{
va_list list;
va_start(list, n);
double result = n;
unsigned int count = 1;
T * pArg = 0;
while (sp > reinterpret_cast<int *>(pArg + 1))
{
pArg = &(va_arg(list, T));
result += *pArg;
count++;
}
va_end(list);
result /= count;
return result;
}
void main()
{
AVERAGE(1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6);
AVERAGE(1.2, 1.3, 1.4, 1.5, 1.6);
AVERAGE(1.2, 1.3, 1.4);
AVERAGE(2, 3, 4);
AVERAGE(2, 3, 4, 5, 6);
}