基本上,我希望能够做的是使用任意数量的任何类型的参数的lambda并将其转换为std :: function。 我尝试过以下方法,但两种方法都不起作用。
std::function([](){});//Complains that std::function is missing template parameters
template <typename T> void foo(function<T> f){}
foo([](){});//Complains that it cannot find a matching candidate
以下代码确实有效,但它不是我想要的,因为它需要明确说明不适用于通用代码的模板参数。
std::function<void()>([](){});
我整个晚上一直在使用功能和模板,我只是想不出来,所以任何帮助都会非常感激。
正如评论中所提到的,我试图这样做的原因是因为我正在尝试使用可变参数模板在C ++中实现currying。不幸的是,这在使用lambdas时非常糟糕。例如,我可以使用函数指针传递标准函数。
template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
foo(bar);
}
但是,我无法弄清楚如何将lambda传递给这样的可变函数。为什么我对将泛型lambda转换为std :: function感兴趣是因为我可以执行以下操作,但最终要求我明确地将模板参数声明为std :: function,这正是我想要避免的。
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function<void()>([](){}));
}
答案 0 :(得分:42)
如果没有显式指定模板参数std::function<T>
,则无法将lambda函数对象作为T
类型的参数传递。模板类型推导尝试将lambda函数的类型与std::function<T>
匹配,在这种情况下它不能做 - 这些类型不一样。模板类型推导不考虑类型之间的转换。
如果您可以通过其他方式来推断类型,则可能。您可以通过将函数参数包装在identity
类型中来实现此目的,以便在尝试将lambda与std::function
匹配时不会失败(因为依赖类型只是被类型推导忽略)并且给出一些其他论点。
template <typename T>
struct identity
{
typedef T type;
};
template <typename... T>
void func(typename identity<std::function<void(T...)>>::type f, T... values) {
f(values...);
}
int main() {
func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8);
return 0;
}
这在您的情况下显然没有用,因为您不希望将值传递到以后。
由于您不想指定模板参数,也不想传递可以推导出模板参数的其他参数,编译器将无法推断出std::function
的类型参数。
答案 1 :(得分:21)
您可以使用专用/回顾性广告。一旦你有这样的工具
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
您可以对所有lambda类型说FFL()
将它们转换为std::function
的正确版本
template <typename... Args> void Callback(std::function<void(Args...)> f){
// store f and call later
}
int main()
{
Callback(FFL([](int a, float b){
// do something
}));
return 0;
}
答案 2 :(得分:13)
如Inferring the call signature of a lambda or arbitrary callable for "make_function"所示,您可以从其(单个)operator()
推断出lambda(或任何其他具有单个调用签名的仿函数)的调用签名:
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename T>
struct get_signature_impl { using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type; };
template<typename R, typename... A>
struct get_signature_impl<R(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(&)(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(*)(A...)> { using type = R(A...); };
template<typename T> using get_signature = typename get_signature_impl<T>::type;
但这是一种相当不灵活的方法;正如R. Martinho Fernandes所说,它不适用于具有多个operator()
s的仿函数,也不适用于具有模板化 operator()
或(C ++ 14)多态lambda的仿函数。这就是为什么bind
推迟其结果类型的推断直到最终的调用尝试。
答案 3 :(得分:7)
可以使用deriation,decltype,variadic模板和一些类型特征为lambda获取所需的std :: function类型:
namespace ambient {
template <typename Function>
struct function_traits : public function_traits<decltype(&Function::operator())> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
typedef ReturnType (*pointer)(Args...);
typedef const std::function<ReturnType(Args...)> function;
};
template <typename Function>
typename function_traits<Function>::function to_function (Function& lambda) {
return static_cast<typename function_traits<Function>::function>(lambda);
}
template <class L>
struct overload_lambda : L {
overload_lambda(L l) : L(l) {}
template <typename... T>
void operator()(T&& ... values){
// here you can access the target std::function with
to_function(*(L*)this)(std::forward<T>(values)...);
}
};
template <class L>
overload_lambda<L> lambda(L l){
return overload_lambda<L>(l);
}
}
我在我的代码中使用它:
ambient::lambda([&](const vector<int>& val){
// some code here //
})(a);
PS:在我的实际案例中,我将这个std :: function对象及其参数保存在一个通用内核对象中,我可以通过虚函数随后执行。
答案 4 :(得分:3)
用std::bind
实现已经实施?
auto sum = [](int a, int b){ return a+b; };
auto inc = std::bind( sum, _1, 1 );
assert( inc(1)==2 );
答案 5 :(得分:3)
这对您来说很有意思:https://gist.github.com/Manu343726/94769034179e2c846acc
这是我一个月前写的一个实验。我们的目标是创建一个类似仿函数的C ++模板,它模拟Haskell的部分调用闭包,即当你使用m-n
argumments调用n
argumments时自动创建m
argumments的闭包。 {1}}参数。
这是该实验可以做的一个例子:
int f( int a, int b, int c, int d)
{
return a+b+c+d;
}
int main()
{
auto foo = haskell::make_function( f );
auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter
std::cout << a , 4 << std::endl; //Prints 10
}
haskell::make_function
使用某些类型特征来处理不同类型的函数实体,包括lambdas:
auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } );
auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax)
auto b = a(3); // b is 6
正如您所看到的,我使用逗号运算符来处理mmimic Haskell语法,但您可以将其更改为调用运算符以实现目标语法。
您可以完全自由地使用代码执行任何操作(检查许可证)。
答案 6 :(得分:1)
在C ++ 17中,有构造函数类型推导。因此,您可以为std :: function模板参数保存一些类型。这不是什么都不是,而是更少。
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function([](){}));
}
答案 7 :(得分:1)
七年后,也许是当时最简单的解决方案,今天仍然有效。
template< char const * (*name) () >
struct user {
auto id() { return name(); }
} ;
用法
constexpr auto lama () { return "Lama"; }
int main( int , char * [] )
{
auto amuser = user< lama >{} ;
cout << boolalpha << amuser.id() << endl ;
}
Lambda爱好者也可以得到
auto cat = [] () constexpr { return "Cat"; } ;
auto sneaky = user< cat >{} ;
cout << boolalpha << sneaky.id() << endl ;
答案 8 :(得分:-1)
使用std::result_of
,如果你只使用函数(没有类/结构,因为声明与std::function
完全不同,而且它真的很丑),你现在可以这样:< /p>
template <typename Func, typename ...Args>
std::result_of_t<Func(Args...)> func(Func function, Args... args) {
/// now do your staff here
}
/// usage:
func([](){printf("lambda function\n"});