[英]Passing (partially) templated template function as std::function(or function pointer)
#include <vector>
#include <functional>
template<class F>
class Foo
{
public:
template <class T>
void std_function(std::function<F(std::vector<T>)> functor)
{
/* something */
}
template <class T>
void func_ptr(F (*funtor)(std::vector<T>))
{
/* something else */
}
};
template<class T, class F>
F bar(std::vector<T>)
{
return F();
}
int main()
{
Foo<double> test;
std::function<double(std::vector<int>)> barz = bar<int, double>;
test.std_function(bar<int, double>); //error 1
test.std_function(barz); //OK 1
test.func_ptr(bar<int, double>); //OK 2
test.std_function(bar<int>); //error 2::1
test.func_ptr(bar<int>); //error 2::2
return 0;
}
Question 1. 问题1。
Line error 1 : I am trying to pass explicitly instantiated template function( bar<int, double>
) as std::function
, but It is not legal. 行错误1 :我试图将显式实例化的模板函数(
bar<int, double>
)作为std::function
传递,但它不合法。
Line OK 1 : If I wrap bar<int, double>
into std::function<double(std::vector<int>)>
and pass wrapped functor, it is legal now. 行OK 1 :如果我将
bar<int, double>
包装到std::function<double(std::vector<int>)>
并传递包装函子,它现在是合法的。
Line OK 2 : If I pass bar<int, double>
through Foo::func_ptr
, which gets function pointer as argument instead of std::function
, it is also legal. 行OK 2 :如果我通过
Foo::func_ptr
传递bar<int, double>
,它将函数指针作为参数而不是std::function
,它也是合法的。
I want to make the Line error 1 legal. 我想让Line 错误1合法。 As in the Line OK 2 , it is possible to pass
bar<int, double>
without any wrapper(unlike Line OK 1 ) and keep same form. 与在行OK 2中一样 ,可以在没有任何包装器的情况下传递
bar<int, double>
(与行OK 1不同)并保持相同的形式。 But, the parameter type is different. 但是,参数类型不同。 I want to pass as
std::function
, not function pointer. 我想传递为
std::function
,而不是函数指针。
Question 2. 问题2。
Line error 2::1 and 2::2 : What I am trying to achieve here is, I want class Foo
to deduce return type of bar
as its class template type F
(for the code above, F
is double
). 行错误2 :: 1和2 :: 2 :我想在这里实现的是,我希望类
Foo
推导出返回类型的bar
作为其类模板类型F
(对于上面的代码, F
是double
)。 So I can just pass as bar<int>
, not bar<int, double>
. 所以我可以传递
bar<int>
,而不是bar<int, double>
。
But It seems to fail deduction, because even if I pass bar<int>
through Foo::func_ptr
, it still produces error. 但它似乎失败了,因为即使我通过
Foo::func_ptr
传递bar<int>
,它仍然会产生错误。 How can I make this code work as my intention? 我怎样才能使这段代码成为我的意图?
For error 1, what's happening is that the compiler is attempting to substitute for T
in std::function
, but it cannot because ultimately a function pointer and a std::function
are different types, and there's no conversion defined for a function pointer to std::function
对于错误1,发生的事情是编译器试图在
std::function
替换T
,但它不能,因为最终函数指针和std::function
是不同的类型,并且没有为函数指针定义转换std::function
This worked: 这有效:
std::function<double(std::vector<int>)> barz = bar<int, double>
Because std::function
was cleverly written with type-erasure to have a constructor that can accept any callable that is convertible to the type it needs. 因为
std::function
巧妙地用type-erasure编写,所以有一个构造函数可以接受任何可转换为它需要的类型的可调用函数。 Note that this isn't the same as type-deduction in the above error because here we are already specifying the template arguments for std::function
. 请注意,这与上面错误中的类型推导不同,因为这里我们已经为
std::function
指定了模板参数。
Note that we can do a little work to get Foo::std_function
to work properly. 请注意,我们可以做一些工作让
Foo::std_function
正常工作。 First change its signature to take a forwarding reference: 首先更改其签名以获取转发参考:
template <class T>
void std_function(T&& functor){/*I'll talk about this in a bit*\}
Then we can construct our std::function
internally (What you're looking to pass into it, I don't know) by using some helper structs to determine its type. 然后我们可以通过使用一些帮助器结构来确定它的类型,从而在内部构建我们的
std::function
(你想要传递给它,我不知道)。 For a function pointer we can do the following: 对于函数指针,我们可以执行以下操作:
// base
template<class... T>
struct function_type_impl;
// specialization for function ptrs and static class fns
template<class Ret, class... Args>
struct function_type_impl<Ret(*)(Args...)>
{
using type = std::function<Ret(Args...)>;
};
// type alias so we don't need to keep typing typename ... ::type
template<class... T>
using function_type = typename function_type_impl<std::decay_t<T>...>::type;
and then we can modify our std_function
signature: 然后我们可以修改我们的
std_function
签名:
template <class T>
void std_function(T&& functor)
{
function_type<T> myFunction = std::forward<T>(functor);
// do something with our std::function
}
Then you can call it as 然后你可以称之为
test.std_function(&::bar<int, double>);
However, if we want to be more complete, and accept functors, lambdas, and even other std::functions
, we can add more specializations: 但是,如果我们想要更完整,并接受仿函数,lambdas,甚至其他
std::functions
,我们可以添加更多的特化:
namespace detail
{
template<class... T>
struct function_type_impl;
template<class Callable>
struct function_type_impl<Callable>
{
using type = typename function_type_impl<decltype(&Callable::operator())>::type;
};
template<class C, class Ret, class... Args>
struct function_type_impl<Ret(C::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<class Ret, class... Args>
struct function_type_impl<Ret(*)(Args...)>
{
using type = std::function<Ret(Args...)>;
};
template<class... T>
using function_type = typename function_type_impl<std::decay_t<T>...>::type;
}// detail namespace
And now the following will work, too: 现在,以下内容也将起作用:
struct MyFunctor
{
double operator()(std::vector<int>) const
{
return 42;
}
};
struct MyFunctor2
{
static double foo(std::vector<int>)
{
return 42;
}
};
int main()
{
Foo<double> test;
std::function<double(std::vector<int>)> barz = bar<int, double>;
test.std_function(&::bar<int, double>);
test.std_function(barz);
test.std_function([](std::vector<int>)->double{return 42;});
test.std_function(MyFunctor{});
test.std_function(MyFunctor2::foo);
}
For errors 2::1 and 2::2, the issue is simpler; 对于错误2 :: 1和2 :: 2,问题更简单; functions do not exist at all until they're completely instantiated.
函数根本不存在,直到它们被完全实例化。 That is, you cannot create a function pointer to a partially templated function.
也就是说,您无法创建指向部分模板化函数的函数指针。 You have to specify all the template arguments when trying to get a function pointer.
在尝试获取函数指针时,必须指定所有模板参数。 Since you have already specified the return type, you can allow the compiler to instantiate the rest of the pointer for you if you explicitly tell
func_ptr
what to deduce for T
: 由于您已经指定了返回类型,因此如果您明确告诉
func_ptr
要为T
推导出什么,您可以允许编译器为您实例化其余的指针:
test.func_ptr<int>(bar);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.