我正在尝试指定一个将通用函数作为参数的函数。函数定义如下:
template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);
如何指定一个将泛型函数作为参数的泛型函数?我试过这个:
template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
return F(args...);
}
包装这个函数:
bool foo(int x, double y) {
return x < y;
}
像这样:
Fun<bool, int, double> func = wrap<bool, int, double, foo>;
但是,不幸的是,这并不能编译。 gcc 8.1 有以下错误信息:
<source>:16:35: error: no matches converting function 'wrap' to type 'Fun<bool, int, double>' {aka 'bool (*)(int, double)'}
Fun<bool, int, double> func = wrap<bool, int, double, foo>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
而clang 6有如下错误:
<source>:16:35: error: address of overloaded function 'wrap' does not match required type 'bool (int, double)'
Fun<bool, int, double> func = wrap<bool, int, double, foo>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
但是,如果我将 TsArgs
替换为 int, double
,就像在 foo()
的签名中一样,它编译得很好,让我相信参数列表中间的那些可变参数模板参数不会像我预期的那样工作。否则我怎么能实现我的目标?
这是 MCVE:
template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);
template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
return F(args...);
}
bool foo(int x, double y) {
return x < y;
}
int main() {
Fun<bool, int, double> func = wrap<bool, int, double, foo>;
return 0;
}
最佳答案
如果你可以使用 C++17,你可以使用 auto
作为模板参数。
这可以大大简化我之前的回答。
或者更好:简化包装器的使用。
如果你定义一个wrapHelper
结构如下
template <typename T, T>
struct wrapHelper;
template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
{
static TRet func (TsArgs ... args)
{ return F(args...); }
};
你可以写wrapper
,使用auto
,如下
template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
{ };
这样就不需要解释返回类型(TRet
)和参数类型(TsArgs...
):它们被推导(在 wrapHelper
) 来自 foo
.
所以,而不是
Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;
你必须写
Fun<bool, int, double> func = wrap<foo>::func;
或者还有
auto func = wrap<foo>::func;
下面是一个完整的编译示例
#include <iostream>
#include <type_traits>
template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);
bool foo(int x, double y)
{ return x < y; }
template <typename T, T>
struct wrapHelper;
template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
{
static TRet func (TsArgs ... args)
{ return F(args...); }
};
template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
{ };
int main()
{
auto func { wrap<foo>::func };
static_assert( std::is_same<decltype(func), Fun<bool, int, double>>{} );
std::cout << func(1, 2.0) << std::endl;
}
关于c++ - 参数列表中间的可变模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50770350/