10

I am trying to use a lambda to pass in place of a function pointer but VS2010 can't seem to convert it. I have tried using std::function like this and it crashes and I have no idea if I am doing this right!

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

It seems strange to me that the compiler can't convert such a lambda to a simple function pointer as it captures no variables - also in the case that it did I wonder what can be done.

Is the type of each lambda unique? So I could hack around with a template function using the lambdas' type as a template argument to generate a unique static function that could be called instead and hopefully optimised out?

UPDATED

The below seems to work but is it safe?

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

UPDATED AGAIN

So with the help given I have come up with the shorter:

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

            method(parameter);
        }
    };


    return &Detail::Bind;
}

This can be used to wrap a lambda with no closure of void(*)(void*) into the equivalent function pointer. It appears that this will become unnecessary in a later version of VS2010.

So how to get this to work for a lambda with closures?

UPDATED AGAIN!

Works for closures in VS2010 - no idea if it's 'safe' though...

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;
}
6
  • Related, wouldn't consider a duplicate. Commented Jul 28, 2010 at 9:02
  • Ah that helped... and I have a work around now from that which I think is safe in my updated question? Commented Jul 28, 2010 at 9:27
  • Seems safe enough. I'll provide you with a more generic solution. You should remove static Signature method; and instead put Signature method; within the function. It's empty so it won't cost anything anyway. Commented Jul 28, 2010 at 9:30
  • Actually I don't quite follow how you can do that? Commented Jul 29, 2010 at 3:09
  • Ok now I get exactly what you mean.. thanks :) Commented Jul 29, 2010 at 3:38

2 Answers 2

5

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

Here's a possible generic work-around, very untested:

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

Let me know if any part is confusing.

Sign up to request clarification or add additional context in comments.

3 Comments

@wb: Heh, decltype just gives you the type of an expression. And && are "rvalue references".
So how can this be made to work for a lambda with a closure? PS: I have updated my question with code for a shorter version for my specific signature case.
@wb: Oops, sorry I missed your comments. Glad you got it solved though. :)
0

If scheduling lambdas/function objects in Concurrency::CurrentScheduler is what you want, it may be worth your while looking at ConcRT Sample Pack v0.32 here

The task_scheduler struct can schedule lambdas asynchronously, but be advised, passing by reference may cause bad things to happen (since we are talking about asynchronous scheduling without a join/wait, a reference on the stack may no longer be valid at time of task execution!)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.