【发布时间】:2020-06-25 13:07:09
【问题描述】:
我有一个提供对其元素的访问的数据结构,以及一些用于迭代它们的循环逻辑。 我需要在循环中调用不同的函数。这些函数都将数据元素作为第一个参数,但允许有任意数量的附加参数。 到目前为止,这听起来像是完美转发的典型案例,所以我的尝试是这样的(通用示例):
template<typename ... Ts>
void looper(
const DataStructure& dataStruct,
void (*func)(const DataElement&, Ts ...),
Ts&& ... args
){
for (Index i{0}; i<dataStruct.someSize(); ++i )
func( dataStruct.elem(i), std::forward<Ts>(args) ... );
}
但是,假设我想使用按值获取参数的函数(如原始类型)调用它,那么我很快就会遇到问题。
void myFunc( const DataElement&, int ){
/* do something */
}
如果我调用 looper 函数并传递int 类型的变量,它将始终被识别为int&,然后我有一个inconsistent parameter pack deduction with 'int' and 'int&':
DataStructure dataStruct;
int myInt {0};
looper( dataStruct, myFunc, myInt ); // <--- this line will cause a compiler error
这是一个非常具有描述性的错误消息,我知道我可以通过将myFunc 设置为const int& 来解决它。
但是,我宁愿编写任何函数,它也可以按值获取参数,并将其指针传递给循环器。我怎样才能做到这一点?
【问题讨论】:
-
为什么不使用基于范围的 for 循环或 ::std::for_each?请注意,您没有转发任何内容,因为您没有使用
Ts的通用引用。 -
我在这里给出的例子被大大简化了。实际上,元素的遍历比一个简单的循环更复杂,因此基于范围的 for 循环或
std::for_each都不会这样做。否则我当然会使用它们。关于你的第二点:我猜你是在引用函数指针签名?那不能采用普遍的参考。但就在下面一行中,looper 实际采用的参数被视为通用引用。 -
请注意,此处可能不适合完美转发。如果在循环的第一次迭代中调用的函数从它的一个参数移动,则该对象的数据将不可用于循环的第二次迭代中的调用。对于这样的事情,最好使用一个好的 ol' lvalue-reference-to-const 代替。
-
啊,好点子,谢谢。移动在实际应用程序中没有意义,因此不会发生,但我仍然希望我的代码能够反映意图。
标签: c++ function-pointers variadic-templates perfect-forwarding