【问题标题】:C++ varargs - Is how I am using them okay or are they bad? Is there a good alternative?C ++ varargs - 我如何使用它们好还是不好?有没有好的选择?
【发布时间】:2013-08-24 23:29:10
【问题描述】:

这样做的最终目标是有一个函数可以接受可变数量的某种类型(相同类型,而不是不同类型)的参数,可以在函数调用中声明。

因为我使用的是 Visual Studio 2010,所以我不能这样做:

MyFunction({1,2,3});

在之前回答的问题中,我发现我可以使用boost::assign::list_of(),但是后来我发现如果你尝试只传递一个参数,这个seems to have a bug of some kind

所以我做了更多的搜索,发现我可以使用可变参数函数来实现我的目标。

void TestFunction2<int>(int count, ...)
{}

但是,我想按类型限制它,所以最终发现我可以使用模板来做到这一点:

template <class T>
void TestFunction(const T& count, ...);

template <>
void TestFunction<int>(const int& count, ...);

不幸的是,像va_list 这样的可变参数显然不喜欢引用。我看到的限制此类类型的示例使用了 const 引用。如果我删除 count 参数的 const 引用方面,它可以按我的意愿工作,但我不知道这是否会导致可怕的副作用开始。

所以我想我的问题是,我在上面最后一个示例中所做的事情是好还是坏?如果不好,有什么好的替代方法,这样我就可以调用具有一个或多个内联参数的函数,例如 int 参数?

【问题讨论】:

  • 我不能在 C++ Visual Studio 2010 使用的版本中使用初始化列表。
  • 啊,那么唯一的选择就是骇人听闻的解决方案(例如包装类或 var_args)。我强烈建议不要使用这种方法……它们会使您的代码更加神秘,更难阅读/编辑/维护。只需声明一个临时数组或其STL 等价物。我知道,我知道这是一个额外的行,但它是更好的形式。
  • 该函数会被调用很多次,每次调用时多出一行声明数组会很不方便。
  • MyFunc(3, new []{1,2,3}); 怎么样(请参阅我更新的答案)....应该适用于您的编译器(我假设)。

标签: c++ visual-studio-2010 c++11 variadic-functions


【解决方案1】:

你想要的是std::initializer_list&lt;T&gt;,不幸的是这需要C++11支持。

另一种选择,几乎同样优雅且易于升级,is to use an array

#include <iostream>
 
template <typename T, size_t N>
void func(T (&s)[N]) {
    for (size_t i = 0; i != N; ++i) {
        std::cout << s[i] << '\n';
    }
}
 
int main() {
    int array[] = {1, 2, 3};
    func(array);
}

当您转向支持初始化列表的编译器时,this can be changed into:

#include <iostream>
 
template <typename T>
void func(std::initializer_list<T> s) {
    for (T const& t: s) {
        std::cout << t << '\n';
    }
}
 
int main() {
    func({1, 2, 3});
}

因此函数和调用站点的更新都将是无痛的。

注意:调用站点可以使用宏完全相似,我建议不要使用这种方法,所谓的收益不值得混淆。

【讨论】:

    【解决方案2】:

    编辑:

    另一种解决方案...如果您的编译器的 IDE部分支持C++11,您可以在调用时初始化std::vector,即

    template <typename T>
    void TestFunction(std::vector<T> vect)
    {
    ....
    }
    
    ....
    
    TestFunction(std::vector<int>{1,2,3});
    

    这种方法的优点是当函数超出范围时,STL 会自动释放分配的内存。

    如果这不起作用,您可以求助于两个班轮......

    template <typename T>
    void TestFunction(std::vector<T> vect)
    {
    ....
    }
    
    ....
    std::vector<int> tmp(1,2,3);
    TestFunction(tmp);
    

    最大的缺点是,这里的内存位于堆栈上,直到您离开该范围(或显式地将向量的大小调整为零长度。

    这两种方法都有一些优点......计数是内置的,您可以访问其他有用的成员函数或附属方法(如std::sort)。

    .......................

    为什么不使用可变参数? 在这里查看答案,例如...
    Is it a good idea to use varargs in a C API to set key value pairs?

    在不符合C+11 的编译器(例如您的 IDE)上,您可以尝试...

    template <typename T>
    TestFunction(const unsigned int count, T * arr)
    
    TestFunction<std::string>(10, new string[] {"One", "Two", "Three"});
    

    (听起来您不能在 IDE 中使用它,但是...) 如果您确信自己只是在现代机器上编译并且主要使用简单类型,那么这是最好/最符合标准的解决方案...

    C++11 开始,您可以使用std::initializer,它位于std::vector

    #include<vector>
    
    template <typename T>
    void TestFunction(const std::initializer_list<T>& v)
    { }
    
    int main()
    {
        TestFunction<double>({1.0, 2.0});
        return 0;
    }
    

    ......................

    ...但是这要求您的编译器为C+11,因此它不是完全可移植的。除了简单类型之外,它也变得更难阅读。

    我知道你说on the function 打电话,但你可能想从可读性和易于编码的方法重新考虑这一点。

    我同意你的部分方法——你想要的是使用template 函数(它处理变量type)。在调用之前,将相同类型元素的集合初始化为临时标准 C 数组或 std::vector/std::list(STL 的数组包装器)。

    http://www.cplusplus.com/doc/tutorial/templates/
    http://www.cplusplus.com/reference/vector/
    http://www.cplusplus.com/reference/list/

    代码行数更多,但可读性和标准化程度更高。

    而不是……

    MyFunction({1,2,3});
    

    用途:

    template <typename T>
    void TestFunction(const int count, T * arr)
    {
      for (unsigned int i = 0; i < count; i++)
      {
        .... arr[i] ... ; //do stuff
        ...
      }
    }
    
    int main()
    {
      int * myArr = {1,2,3};
      TestFuntion<int>(3, myArr);
    }
    

    ...或...

    #include <vector>
    template <typename T>
    void TestFunction(std::vector<T> vect)
    {
      for (unsigned int i = 0; i < vect.size(); i++)
      {
        .... vect[i] ... ; //do stuff
        ...
      }
    }
    
    int main()
    {
      std::vector<int> myVect;
      myVect.push_back(1);
      myVect.push_back(2);
      myVect.push_back(3);
      TestFuntion<int>(myVect);
    }
    

    std::list 也是完全可以接受的,并且性能可能会更好,具体取决于您的用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-15
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 2013-10-05
      相关资源
      最近更新 更多