提问者:小点点

完美地将函数参数转发到函数指针:通过值传递呢?


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

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&;,然后我就有了一个不一致的参数包推导,其中有'int'和'int&;':

DataStructure dataStruct;
int myInt {0};
looper( dataStruct, myFunc, myInt ); // <--- this line will cause a compiler error

这是一个描述性很强的错误消息,我知道,例如,我可以通过使myfunc取一个const int&;来解决它。

然而,我宁愿能够编写任何函数,这些函数也可以通过值获取参数,并将其指针传递给循环程序。 我怎么才能做到呢?


共1个答案

匿名用户

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&;,则不能传递常量int&;。 这可能会导致混乱的错误消息。