完美转发函数参数到函数指针:按值传递呢?

Perfect forwarding function parameters to function pointer: What about passing by value?

我有一个数据结构,它提供对其元素的访问,以及一些用于如何迭代它们的循环逻辑。 我需要在循环内调用不同的函数。这些函数都将数据元素作为第一个参数,但应允许有任意数量的附加参数。 到目前为止,这听起来像是完美转发的典型案例,所以我的尝试是这样的(一般示例):

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 */
}

如果我调用循环函数并传递一个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&.

来解决它

但是,我宁愿能够只编写任何函数,它也可以按值获取参数,并将其指针传递给循环程序。我怎样才能做到这一点?

Args 将推导 两次 ,一次用于函数签名,一次用于参数。它们不一定需要完全相同:参数被推导出为 int&,因为它是从局部变量推导出来的,但它不对应于函数签名(即 int)。

你可以拆分它们,像这样:

template<typename... Ts_fun_args, typename... Ts_param_args>
void looper(
    const DataStructure& dataStruct,
    void (*func)(const DataElement&, Ts_fun_args ...),
    Ts_param_args&& ... args
){
    for (Index i{0}; i<dataStruct.someSize(); ++i )
        func( dataStruct.elem(i), std::forward<Ts_param_args>(args) ... );
}

请注意 Ts_fun_args 需要转换为 Ts_param_args。如果你有一个函数签名,例如 int&,你不能传递 const int&。这可能会导致出现令人困惑的错误消息。