我正在编写一个模板包装器函数,可以应用于具有不同数量/类型参数的函数。我有一些代码可以工作,但我正试图将更多的参数更改为模板参数。
工作代码:
#include <iostream>
int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...
template<typename ...ARGS>
int wrapper(int (*func)(ARGS...), ARGS... args) { return (*func)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool>(func0, b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
现在我想让int (*func)(ARGS...)
也成为模板参数。(这是出于性能原因。我希望指针回到包装器中,因为我使用它的方式阻止了编译器将其优化出来。
这是我想到的(唯一的区别是我把一个实参变成了一个模板形参):
#include <iostream>
int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...
template<typename ...ARGS, int (*FUNC)(ARGS...)>
int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
这不能编译。它表明:
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
ASM generation compiler returned: 1
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
Execution build compiler returned: 1
(链接到编译器资源管理器)
对我来说,这看起来像是编译器的问题,但是GCC和Clang都同意这一点,所以也许不是。
无论如何,我怎样才能使这个模板正确编译与模板指针到一个函数?
编辑:通过实例化函数模板解决重复标志编译问题我认为这个问题的核心和我的问题是一样的,但是,它缺乏一个解决方案,允许将指针传递给函数(不仅仅是它的类型)作为模板参数。
这不起作用,因为pack参数(包含...
的参数)消耗所有剩余的参数。不能显式指定其后的所有参数,必须推导。
通常你这样写包装器:
template <typename F, typename ...P>
int wrapper(F &&func, P &&... params)
{
return std::forward<F>(func)(std::forward<P>(params)...) * 10;
}
(如果函数在包装器内部被多次调用,除了最后一次调用外,所有调用都不能使用std::forward
)
这将通过引用传递函数,这应该与使用函数指针完全相同,但我没有理由相信它会阻止编译器优化它。
你可以通过传递std::integral_constant<decltype(&func0), func0>{}
而不是func0
来强制函数在模板参数中编码,但是,我再次认为它不会改变任何东西。
第二个代码段无效因为:
类型参数包不能在其自己的参数子句中展开.
As from [temp.param]/17:
如果模板参数是一个类型参数,在其可选的标识符之前有一个省号,或者是一个参数声明声明了一个包([dcl.fct]),那么模板参数是一个模板参数包。参数声明类型包含一个或多个未展开包的模板参数包是一个包展开. ...作为包展开的模板形参包不能展开在同一个template-parameter-list中声明的模板形参包.
所以考虑下面的invalid例子:
template<typename... Ts, Ts... vals> struct mytuple {}; //invalid
上面的例子无效,因为模板类型参数包Ts
不能在它自己的参数列表中展开。
出于同样的原因,您的代码示例无效。例如,第二个代码段的简化版本不能在msvc中编译。