5

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

当我使用 Visual Studio 2010 时,我不能这样做:

MyFunction({1,2,3});

在之前回答的问题中,我发现我可以使用boost::assign::list_of(),但是我后来发现,如果您尝试只传递一个参数,这似乎有某种错误。

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

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 引用方面,它会按我的意愿工作,但我不知道这是否会导致可怕的副作用,或者如果整个 varargs 事情是一个坏主意首先。

所以我想我的问题是,我在上面的最后一个例子中所做的是好还是坏?如果不好,有什么好的选择,这样我就可以用一个或多个内联参数调用函数,比如int参数?

4

2 回答 2

4

您想要的是std::initializer_list<T>,不幸的是,这需要 C++11 支持。

另一种几乎同样优雅且易于升级的替代方法是使用数组

#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);
}

当您继续使用支持初始化列表的编译器时,可以将其更改为

#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});
}

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

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

于 2013-08-22T11:00:47.140 回答
0

编辑:

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

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)。

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

为什么不使用可变参数?例如,请参阅此处的答案......
在 C API 中使用可变参数来设置键值对是个好主意吗?

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::initializerwhich is in 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/

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

IE

而不是...

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也将是完全可以接受的,并且可能会表现得更好,具体取决于您的用例。

于 2013-08-22T10:01:15.607 回答