验证变量参数是预期类型

时间:2011-06-24 18:04:58

标签: c++ arguments variadic-functions

我正在编写一个函数,它将采用可变数量的参数。我将参数的数量传递给函数,然后遍历参数列表。

每个传递的参数都应该是一个整数。我将把这个整数添加到一个整数向量中,稍后将使用它。

我想确保一些小丑不会尝试将此函数传递给将来的整数。我认识到我可以检查来自va_arg的当前参数以确保它不是NULL并且我可以使用类似isanum(va_arg())来确定它是否是有效整数。我想我甚至可以检查sizeof(va_arg)并将其与sizeof(int)进行比较并确保它们相等。

我是否可以运行其他检查以验证我是否已传递有效整数?

提前感谢您的帮助

9 个答案:

答案 0 :(得分:8)

没有明智的方法可以做到这一点。变量参数函数通过将参数的所有原始二进制表示连接到堆栈上的一大块数据来工作。所以它依赖于调用者和被调用者就争论的数量和类型达成一致(否则你将最终阅读int,就像它是float一样。)

至于你的具体想法:

  • va_arg()是一个宏,可以简单地将原始堆栈数据的某些字节解释为您指定的任何类型。因此,在其上调用sizeof()只会告诉您所要求的数据类型的大小。

  • 通常,没有形成无效整数的原始二进制数据模式。因此,假设的isanum()无效。

答案 1 :(得分:4)

  

每个传递的参数都应该是一个整数。

如果您有C ++ 0x编译器,我建议使用initializer_list<int>而不是varargs:

#include <initializer_list>

void foo(std::initializer_list<int> numbers)
{
    my_vector.insert(my_vector.end(), numbers.begin(), numbers.end());
}

int main()
{
    foo( {2, 3, 5, 7} );
}

这是直截了当且完全类型安全的。

答案 2 :(得分:3)

  

每个传递的参数都应该是   整数。我会补充一下   整数到整数的向量   将在以后使用。

那为什么不接受整数向量?

void AddIntegers(const std::vector<int>& vec);

然后,您可以使用迭代器将向量连接在一起。

或制作如下界面:

void AddInteger(int newInt);

甚至这个:

void AddIntegers(const int* integers, unsigned int numIntegers);

template <unsigned int Size>
void AddIntegers(int (&integers)[Size])
{
    AddIntegers(integers, Size);
}

int main()
{
    int i[] = {1, 2, 3, 4};
    AddIntegers(i);
}

如果您需要使用C ++ 03编译器,这些将起作用。如果你有一个C ++ 0x编译器,那么可以使用更好的解决方案。

答案 3 :(得分:1)

变量参数在设计上是不安全的。您无法以任何方式检查用户是否传递了正确的类型。使用可变参数模板来拯救C ++ 0x但现在并没有多少编译器支持它(只有GCC afaik)。

答案 4 :(得分:1)

不幸的是,确实没有办法做到这一点。像printf()这样的函数可以通过传递无效或错误数量的参数来轻易搞清楚。

在C ++中,这是一项高级功能,需要使用此类代码进行编程,以确保传递正确的参数。

答案 5 :(得分:1)

您无法使用varargs进行任何类型的检查。我建议使用迭代器范围(如标准库函数)或可能使用std::vector<int>。这样就无法破坏这些类型。

答案 6 :(得分:0)

由于您使用的是C ++,如何重载某些运算符并逐个传递参数?例如

class MyFunction {
  std::vector<int> param;
  public:
  MyFunction() { /* some initialisation? */ }
  MyFunction &operator,(int eatMe) {
    param.push_back(eatMe);
    return *this;
  }
  ~MyFunction() {
     //the implementation of your function goes here
  }
}

然后你可以这样称呼它:

MyFunction(),2,3,5,7;

注意,使用逗号运算符可能看起来很可怕,但在这种情况下它实际上非常有用。它是尽可能最低的左关联运算符。

如果你的函数需要一些额外的参数,不仅是int - s的未知长度,你可以在构造函数中传递它们。

如果有人使用的不是int,则会使用默认的逗号运算符(评估左侧,丢弃,评估右侧)。如果你不喜欢这样 - 选择一个不同的运营商,例如类似流<<或类似促进%

答案 7 :(得分:0)

如果你被限制在C ++ 03并且你的所有参数都应该是整数,那么一个解决方案就是简单地隐藏变量参数函数(例如在'detail'命名空间中)并为1创建一系列重载函数到N量的论点。这些函数将是简单的内联函数,用于将调用转发给实际函数的vararg版本。这样,你有一个真正的实现,没有运行时开销,并且你向调用者公开了一个类型安全的接口(如果他需要超过N个参数,调用者总是可以使用vararg版本。)

Boost.PP也可以帮助生成这些类型的重复模式。

当然,如果你有一定程度的C ++ 0x支持,那么问题可以通过多种方式解决,包括initializer_list或可变参数模板。

答案 8 :(得分:0)

为了说明我对CygnusX1答案的评论,你可以这样做:

class MyFunction {
  std::vector<int> params;
  public:
  MyFunction() { (*this)(); }
  MyFunction(int eatMe) { (*this)(eatMe); }
  MyFunction& operator()(int eatMe) {
    params.push_back(eatMe);
    return *this;
  }
  void operator()() { 
    // use params to do something interesting
  }
}

MyFunction(2)(3)(5)(7)();