我想要一个函数,它接受一个指向函数的指针,并转发函数指针类型本身给定的所有参数,如下所示:
template < typename RET, typename ... ARGS >
auto Do1( RET(*ptr)(ARGS...), ARGS... args )
{
(*ptr)(std::forward<ARGS>( args )...);
}
int main ()
{
int i=4;
Do1( &Ex1, i );
Do1( &Ex2, i ); //fails!
Do1( &Ex3, i+1 ); // fails
}
要调用的函数用于这两个示例:
void Ex1( int i){ std::cout << __PRETTY_FUNCTION__ << " " << i << std::endl; i=10;}
void Ex2( int& i){ std::cout << __PRETTY_FUNCTION__ << " " << i << std::endl; i=20;}
void Ex3( int&& i){ std::cout << __PRETTY_FUNCTION__ << " " << i << std::endl; i=30;}
如果发生故障
Ex2
和
Ex3
简单地说,当它尝试两次推导参数列表的类型时,结果是不同的。编译器抱怨:
main.cpp:57:22: error: no matching function for call to 'Do1(void (*)(int&), int&)'
Do1( &Ex2, i ); //fails!
^
main.cpp:33:10: note: candidate: 'template<class RET, class ... ARGS> auto Do1(RET (*)(ARGS ...), ARGS ...)'
auto Do1( RET(*ptr)(ARGS...), ARGS... args )
^~~
main.cpp:33:10: note: template argument deduction/substitution failed:
main.cpp:57:22: note: inconsistent parameter pack deduction with 'int&' and 'int'
之后,我尝试使用以下方法来解决问题,因为我只提取了一次类型,推导出args列表,然后再次转发到中间lambda,如下所示:
template < typename RET, typename ... ARGS >
auto Do2( RET(*ptr)(ARGS...) )
{
return [ptr]( ARGS ... args )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
(*ptr)(std::forward<ARGS>(args)...);
};
}
int main ()
{
int i=4;
Do1( &Ex1, i );
Do1( &Ex2, i ); //fails!
Do1( &Ex3, i+1 ); // fails
Do2( &Ex1 )( i );
std::cout << "now i: " << i << std::endl;
std::cout << std::endl;
Do2( &Ex2 )( i );
std::cout << "now i: " << i << std::endl;
std::cout << std::endl;
Do2( &Ex3 )( i+1 );
std::cout << "now i: " << i << std::endl;
std::cout << std::endl;
}
问:在任何情况下,有没有办法修复第一种方法来消除中间lambda?如果不是,中间lambda的解决方案是否设计得“很好”,特别是所有“转发”的东西,这样我就不会创建一些副本或其他意想不到的行为?
编辑:
这只是一个简化的例子。我不是要写一份
std::invoke
. 所以在我的现实世界中有很多代码需要在
Do
方法本身。
从函数指针类型获取所需类型很重要,因为我必须在内部执行一些检查
做
与函数指针提供的类型相关,并且
不
从给定的附加参数中,我提供了从用户代码到
做
方法。