【问题标题】:C++0x Lambda to function pointer in VS 2010C++0x Lambda 到 VS 2010 中的函数指针
【发布时间】:2010-07-28 08:55:21
【问题描述】:

我正在尝试使用 lambda 来代替函数指针,但 VS2010 似乎无法转换它。我试过像这样使用 std::function 并且它崩溃了,我不知道我这样做是否正确!

#include <windows.h>
#include <conio.h>

#include <functional>
#include <iostream>

#include <concrt.h>


void main()
{
    std::function<void(void*)> f = [](void*) -> void
    {
        std::cout << "Hello\n";
    };


    Concurrency::CurrentScheduler::ScheduleTask(f.target<void(void*)>(), 0);

    getch();
}

编译器无法将这样的 lambda 转换为简单的函数指针,因为它不捕获任何变量,这对我来说似乎很奇怪——即使在这种情况下,我也想知道可以做什么。

每个 lambda 的类型是否唯一?因此,我可以使用 lambda 类型作为模板参数来修改模板函数,以生成一个独特的静态函数,该函数可以被调用并有望优化?

更新

以下似乎可行,但安全吗?

#include <windows.h>
#include <conio.h>

#include <iostream>

#include <concrt.h>


template<typename Signature>
struct Bind
{
    static Signature method;

    static void Call(void* parameter)
    {
        method(parameter);
    }
};


template<typename Signature>
Signature Bind<Signature>::method;


template<typename Signature>
void ScheduleTask(Signature method)
{
    Bind<Signature>::method = method;
    Concurrency::CurrentScheduler::ScheduleTask(&Bind<Signature>::Call,0);
}


void main()
{
    ScheduleTask
    (   
        [](void*)
        {
            std::cout << "Hello";
        }
    );


    ScheduleTask
    (   
        [](void*)
        {
            std::cout << " there!\n";
        }
    );


    getch();
}

再次更新

所以在给定的帮助下,我想出了更短的:

template<typename Signature>
void (*LambdaBind(Signature))(void*)
{
    struct Detail
    {
        static void Bind(void* parameter)
        {
            Signature method;

            method(parameter);
        }
    };


    return &Detail::Bind;
}

这可用于将没有 void(*)(void*) 闭包的 lambda 包装到等效的函数指针中。看来这在 VS2010 的更高版本中将变得不必要了。

那么如何让它对带有闭包的 lambda 起作用?

再次更新!

适用于 VS2010 中的闭包 - 虽然不知道它是否“安全”...

template<typename Signature>
struct Detail2
{
    static std::function<void(void*)> method;


    static void Bind(void* parameter)
    {
        method(parameter);
    }
};


template<typename Signature>
std::function<void(void*)> Detail2<Signature>::method;


template<typename Signature>
void (*LambdaBind2(Signature method))(void*)
{
    Detail2<Signature>::method = method;
    return &Detail2<Signature>::Bind;
}

【问题讨论】:

  • Related,不会考虑重复。
  • 啊,这有帮助...而且我现在有一个解决方法,我认为在我更新的问题中是安全的?
  • 似乎足够安全。我将为您提供更通用的解决方案。您应该删除 static Signature method; 并将 Signature method; 放在函数中。它是空的,所以无论如何它不会花费任何费用。
  • 其实我不太明白你是怎么做到的?
  • 好的,现在我明白你的意思了.. 谢谢 :)

标签: c++ visual-studio-2010 lambda c++11


【解决方案1】:

This feature of lambda's was added after VS2010 implemented them, so they don't exist in it yet.

这是一个可能的通用解决方法,未经测试:

#include <functional>
#include <iostream>

namespace detail
{
    // helper specializations,
    // define forwarding methods
    template <typename Lambda, typename Func>
    struct lambda_wrapper;

    #define DEFINE_OPERATOR \
            typedef decltype(&call) function_type; \
            operator function_type(void) const \
            { \
                return &call; \
            }

    template <typename Lambda, typename C, typename R>
    struct lambda_wrapper<Lambda, R (C::*)(void) const>
    {
        static R call(void)
        {
            Lambda x;
            return x();
        }

        DEFINE_OPERATOR
    };

    template <typename Lambda, typename C, typename R,
                typename A0>
    struct lambda_wrapper<Lambda, R (C::*)(A0) const>
    {
        static R call(A0&& p0)
        {
            Lambda x;
            return x(std::forward<A0>(p0));
        }

        DEFINE_OPERATOR
    };

    // and so on
    #undef DEFINE_OPERATOR
}

// wraps a lambda and provides 
// a way to call it statically
template <typename Lambda>
struct lambda_wrapper :
        detail::lambda_wrapper<Lambda, decltype(&Lambda::operator())>
{};

template <typename Lambda>
lambda_wrapper<Lambda> wrap_lambda(const Lambda&)
{
    return lambda_wrapper<Lambda>();
}

int main(void)
{
    auto l = [](){ std::cout << "im broked :(" << std::endl; };
    std::function<void(void)> f = wrap_lambda(l);

    f();
}

如果有任何令人困惑的部分,请告诉我。

【讨论】:

  • @wb: 嘿,decltype 只是给你一个表达式的类型。而&amp;&amp; 是“右值引用”。
  • 那么如何使它适用于带有闭包的 lambda 呢? PS:我已经用代码更新了我的问题,为我的特定签名案例提供了一个较短的版本。
  • @wb:哎呀,对不起,我错过了你的 cmets。很高兴你解决了它。 :)
【解决方案2】:

如果您想要在 Concurrency::CurrentScheduler 中调度 lambdas/函数对象,那么在查看 ConcRT Sample Pack v0.32 here 时可能值得您参考

task_scheduler 结构可以异步调度 lambda,但请注意,通过引用传递可能会导致不好的事情发生(因为我们谈论的是没有加入/等待的异步调度,堆栈上的引用在任务执行时可能不再有效!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 2012-10-28
    • 2021-10-05
    • 1970-01-01
    • 2011-02-03
    • 2017-10-02
    相关资源
    最近更新 更多