C++ 使用参数包将lambda强制转换为std::函数
关于将lambda强制转换为C++ 使用参数包将lambda强制转换为std::函数,c++,lambda,variadic-templates,c++17,C++,Lambda,Variadic Templates,C++17,关于将lambda强制转换为std::functions有几个问题,但是我还没有看到一个使用参数包作为参数列表的问题。在我的g++(7.1.1-4)版本中,这似乎被破坏了,可能只是不受支持。那么这是合法的c++17(按标准)?若否,原因为何 #include <functional> template <typename TReturn, typename ... TArgs> void Functor(std::function<TReturn (TArgs..
std::function
s有几个问题,但是我还没有看到一个使用参数包作为参数列表的问题。在我的g++(7.1.1-4)版本中,这似乎被破坏了,可能只是不受支持。那么这是合法的c++17(按标准)?若否,原因为何
#include <functional>
template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int, int, int>(x);
return 0;
}
这失败了:
#include <functional>
template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int, int, int>(x);
return 0;
}
这不会编译,因为lambda不是std::function
(或派生自lambda的函数),这与不提供任何类型就无法调用它的原因相同
非变量版本没有这个问题,因为您已经提供了所有类型
但实际上,你想要的是:
template <typename F>
void Functor(F ) {}
模板
无效函子(F){}
这不会让你失去任何类型的安全。它使用的
std::function
会丢失类型信息,因为该类模板用于类型擦除。问题是编译器不知道您打算将int,int
作为TArgs
的整体,因此尝试从参数f
推断TArgs
的其余部分
例如,这将是有效的:
Functor<int, int, int>(std::function<int(int, int, char, float)>{});
// TArgs := {int, int, [...] char, float}
或者您可以使用未分解的签名Sig
编写Functor
:
template <Sig>
void Functor(std::function<Sig> f) {}
下面是一个解决方案,您可以调用
functor
,而无需指定其模板参数:
#include <functional>
#include <type_traits>
template <class T> struct Fun_trait {};
template <class T, class... Args, class Ret>
struct Fun_trait<auto (T::*) (Args...) const -> Ret>
{
using F = std::function<auto (Args...) -> Ret>;
};
template <class TReturn, class... TArgs>
void functor(std::function<TReturn (TArgs...)> f) {}
template <class F>
std::void_t<decltype(&F::operator())>
functor(F f)
{
return functor<typename Fun_trait<decltype(&F::operator())>::F>(f);
};
int main(int argc, char * argv[])
{
auto x = [] (int a, int b) { return a * b; };
// nice and easy:
functor(x);
return 0;
}
#包括
#包括
模板结构Fun_trait{};
模板
结构乐趣\u特质Ret>
{
使用F=std::function Ret>;
};
模板
空函子(std::函数f){}
模板
std::void\u t
函子(F)
{
返回函子(f);
};
int main(int argc,char*argv[])
{
autox=[](inta,intb){返回a*b;};
//简单明了:
函子(x);
返回0;
}
这只是一个懒散的初稿,让你开始。您需要扩展它以支持转发和非常量操作符()
它分两个阶段工作:
首先,我们有Fun\u trait
who-对于指针方法类型(例如lambda的操作符()
),为所需的std::function
参数类型定义了一个别名F
接下来,我们有一个函数的重载functor
,它通过SFINAE withstd::void\u t
仅适用于带有非重载操作符()的functor(例如lambda)然后使用上面的特性调用主函数functor
,并推导出正确的模板参数。如果要调用模板中的std::function
,则将lambda强制转换为std::function
很少是一个好主意std::function
是类型擦除,模板类型擦除只有在您将其“传递”到其他地方并/或返回时才有意义
在任何情况下,请尝试以下方法:
template <class Sig>
void Functor(std::function<Sig> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int(int, int)>(x);
return 0;
}
模板
空函子(std::函数f){}
int main(int argc,char*argv[]){
autox=[](inta,intb){返回a*b;};
函子(x);
返回0;
}
但你真的应该这么做
template <class F>
void Functor(F f) {}
模板
无效函子(F){}
这是完全类型安全的
如果你想提前检查类型,你可以写
template<class Sig, class F>
struct signature_compatible;
template<class R, class...Args, class F>
struct signature_compatible<R(Args...), F> :
std::is_consructible< R, std::result_of_t<F(Args...)>>
{};
模板
结构签名兼容;
模板
结构签名\u兼容:
std::是否可构造
{};
那就做吧
template <class Sig, class F>
void Functor(F f) {
static_assert( signature_compatible<Sig, F&>::value, "bad signature" );
}
模板
虚空函子(F){
静态断言(签名兼容::值,“坏签名”);
}
但只有当你真的需要的时候
template <class Sig>
void Functor(std::function<Sig> f) {}
int main(int argc, char * argv[]) {
auto x = [] (int a, int b) { return a * b; };
Functor<int(int, int)>(x);
return 0;
}
template <class F>
void Functor(F f) {}
template<class Sig, class F>
struct signature_compatible;
template<class R, class...Args, class F>
struct signature_compatible<R(Args...), F> :
std::is_consructible< R, std::result_of_t<F(Args...)>>
{};
template <class Sig, class F>
void Functor(F f) {
static_assert( signature_compatible<Sig, F&>::value, "bad signature" );
}