使用可变参数模板函数来执行此操作。当然不需要通过容器 of T
到一个函数作为变量参数列表的替代T
.
下面是一个 C++11 程序示例:
#include <iostream>
#include <vector>
// Base case with 0 arguments
std::vector<int> foo() {
return std::vector<int>();
}
// General case with 1 + N arguments of type `int`.
// Return a `vector<int>` populated with the arguments.
template<typename ...Args>
std::vector<int> foo(int const & first, Args const &... rest)
{
std::vector<int> h(1,first);
if (sizeof...(rest)) {
std::vector<int> t = foo(rest...);
h.insert(h.end(),t.begin(),t.end());
}
return h;
}
struct bar{};
using namespace std;
int main()
{
int i = 1, j = 2, k = 3;
vector<int> v0 = foo(i,j);
vector<int> v1 = foo(i,j,k);
cout << v0.size() << endl;
cout << v1.size() << endl;
// bar b;
// vector<int> v2 = foo(i,j,k,b); <-- Compile error
return 0;
}
乍一看,它的定义似乎是foo
一般而言
case 并不限制所有参数为(可转换为)int
,
但事实上它们必须是 - 见证不可编译的初始化v2
.
继续回应OP的评论
如何编写一个类型安全的函数,该函数采用任意给定的多个参数
类型,包括 const 引用类型,在 C++11 中不是一个有问题的问题。
核心语言提供了这种语法模式来执行此操作:
// Base case, 0 arguments
R Func() { [---] }
// General case, 1 + N arguments
template<typename U ...Args>
R Func(T [Modifier], Args [Modifier] ...args) {
[---]
if (sizeof...(args)) {
[---Func(args)---]
}
[---]
}
where [---]
, [---Func(args)---]
可以填写。
函数模板foo
在上面的示例程序中应用了这种模式。
你问:What if foo
是否有比创建容器更复杂的事情?答案是:无论出现什么复杂情况,您都可以适当地应用该模式
是 - 就像您应用该模式一样:
for( [---];[---];[---]) {
[---]
}
适当地,无论有什么并发症。可变参数函数模板
模式需要更多的习惯,因为它涉及递归模板
实例化——仅此而已。
您似乎混淆了两件事:
- A) 接受可变数量的 T 类型参数的函数。
- B) 一个接受 C 类型参数的函数,其中 C 是一个
T 类型对象的可迭代序列。
在你自己的回答中你说:
采用可变数量参数的函数可以写为:
void foo(std::initializer_list<rvalue_reference_wrapper<Base>> args)
{
for (Base& arg : args)
{
arg.virtFunc();
doStuffWithBaseRef(arg);
}
}
那简直就是not一个A),它是一个B)。
在这里和您的评论中,您都表现出希望能够迭代
论点函数体内的可变参数函数。在C/C++中,有
没有机制可以迭代函数的参数(除非它是
Avarargs功能 http://en.wikipedia.org/wiki/Variadic_function#Example_in_C根据标准 C)
而你还没有发明一种。如果函数是 B) 类型,那么显然
函数可以迭代T
是的成员 the C
这是函数的参数。
这就是你正在做的foo
在你的回答中。
如果在 C++ 中不可能编写 A 类型的函数),那么作为一个拼凑
我们可以替换 B 类型的函数)。但 A) 类型的函数是
使用所示的类型安全可变参数模板模式进行常规编码,并且没有这样的拼凑
被要求。如果您想要的是 A) 类型的函数,请使用该模式
并掌握它的窍门。如果你想要的是一个迭代的函数
序列的成员T
,然后像你所做的那样:写一个需要
参数是一个可迭代序列T
.
被认为是一种可能的手段传递 [const] 的可迭代序列
参考对于函数,您的解决方案具有禁用限制
这些引用只能是对临时对象的引用是
在初始化列表中构造,不是对预先存在的对象的引用
- 因为它们几乎总是在真实代码中。例如,虽然
代码:
foo({Derived1(), Derived2()});
将按照预期编译并运行foo
, Derived1
,
Derived2
在你的回答中,更有可能的情况是:
Derived1 d1; // <- Comes from somewhere
Derived2 d2; // <- Comes from somewhere
foo({d1,d2}); // <- Error
不会编译,因为左值T
无法绑定到T&&
。出行
这个,你必须写:
Derived1 d1; // <- Comes from somewhere
Derived2 d2; // <- Comes from somewhere
foo({Derived1(d1),Derived2(d2)});
所以现在,你正在建造临时的copies“论点”,以及
一个initalizer_list
of rvalue_reference_wrapper
的参考文献
临时副本,以便您可以迭代对其中临时副本的引用foo
.
好吧,如果你必须使用“参数”的副本,那就是多余的
费心构建一个序列对副本的引用。只是
将“参数”复制到任何合适的容器中并传递foo
一个 [const] 引用
对此。这不会停止foo
从迭代 [const] 引用到
容器成员就像现在一样。
看来您可能在一定程度上被这个问题所困扰:什么
将是一个合适的容器,用于容纳从多态派生的各种类型的对象
根据 B
,如果不是指向动态分配对象的原始指针的容器?
对此,一个毫无争议的答案是:std::
容器<std::shared_ptr<B>>
,
where 容器是一个标准容器模板(向量、列表等)
为您的应用程序提供适当的接口。更普遍的说法是所谓的智能指针模板,std::shared_ptr<T>
(文档 http://en.cppreference.com/w/cpp/memory/shared_ptr) and
std::unique_ptr<T>
(文档 http://en.cppreference.com/w/cpp/memory/unique_ptr)
是标准 C++11 资源,用于避免暴露原始动态指针。
您似乎也可能被吸引std::initializer_list
为了
将可迭代序列传递给函数,因为您可以轻松地
可以在使用时使用大括号初始化器构造一个。那个方便
可以保留而不处理原始动态指针or智能指针。
例如。
void foo(std::initializer_list<std::shared_ptr<Base>> args)
{
for (auto arg : args)
{
arg->virtFunc();
doStuffWithBaseRef(*arg);
}
}
std::shared_ptr<Base> b1(new Derived1);
std::shared_ptr<Base> b2(new Derived2);
foo({b1,b2});
会好的,所以也会:
void foo(std::initializer_list<Base *> args)
{
for (auto arg : args)
{
arg->virtFunc();
doStuffWithBaseRef(*arg);
}
}
Derived1 d1;
Derived2 d2;
foo({&d1,&d2});