如何将拉姆达转换为标准::使用函数模板如何将拉姆达转换为标准::使用函数模板(How to conv

2019-06-17 09:50发布

基本上,我希望能够做的就是采取一个lambda与任意数量的任何类型的参数,并将其转换为一个std ::功能。 我已经试过以下既不方法的工作。

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 ++中。 不幸的是,使用Lambda表达式时失败可怕。 例如,我可以通过使用函数指针的标准功能。

template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
    foo(bar);
}

然而,我无法弄清楚如何将拉姆达传递给这样的可变参数函数。 为什么我感兴趣的是一个通用的拉姆达转换成的std ::功能是因为我可以做以下,但它结束了要求我明确指出模板参数为std这正是我想避免::功能。

template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
    foo(std::function<void()>([](){}));
}

Answer 1:

不能传递lambda函数对象作为类型的参数std::function<T>而不显式指定的模板参数T 。 模板类型推演尝试匹配您的lambda表达式到类型std::function<T>它只是不能在这种情况下做的-这些类型是不一样的。 模板类型推演不考虑类型之间的转换。

这是可能的,如果你可以给它一些其他的方式来推断类型。 您可以通过在包装函数的参数做这个identity类型,以便它不尝试匹配的拉姆达失败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的参数。



Answer 2:

您可以使用专用/追溯演员 。 一旦你有了这样的工具

#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;
}

你可以说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;
}

显示



Answer 3:

截至所示推断拉姆达或任意调用为“make_function”的号召签名 ,你可以从它的(单)推断一个lambda的调用签名(或任何其他函子与一个单一的呼叫签名) operator()

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费尔南德斯说,它不会与多个函子工作operator() S,也不用于与模板函子operator()或为(C ++ 14)多晶型的lambda。 这就是为什么bind推迟其结果类型推断,直到最终呼叫尝试。



Answer 4:

这是可能使用的推导,decltype,和可变参数模板和一些类型的特征,以获得拉姆达所需的std ::函数类型:

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 ::函数对象及其参数,我可以通过虚拟功能需求后执行的通用内核对象内。

     



Answer 5:

是不是哗众取宠已经与实施std::bind

auto sum = [](int a, int b){ return a+b; };
auto inc = std::bind( sum, _1, 1 );
assert( inc(1)==2 );


Answer 6:

这可能是对你有意思: https://gist.github.com/Manu343726/94769034179e2c846acc

这是我一个月前写的实验。 我们的目标是创造一个仿函数类C ++模板,模仿Haskell的部分通话关闭,即自动创建一个封闭的mn当你调用argumments n argumments与功能m的参数。

这是一个什么样这个实验是cappable做一个例子:

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使用某种类型的特点采取不同类型的功能实体的护理,包括lambda表达式:

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语法,但你可以将其更改为调用操作来实现自己的目标的语法。

你完全可以自由地做你想要的任何代码(检查许可证)。



Answer 7:

在C ++ 17有构造型扣。 所以,你可以节省一些打字的的std ::函数模板参数。 这是不太什么,但少了几分。

template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
   foo(std::function([](){}));
}    


文章来源: How to convert a lambda to an std::function using templates