17

Please look at the following C++0x lambda related code:

typedef uint64_t (*WEIGHT_FUNC)(void* param);
typedef std::map<std::string, WEIGHT_FUNC> CallbackTable;

CallbackTable table;
table["rand_weight"] = [](void* param) -> uint64_t
{
  return (rand() % 100 + 1);
};

I got an error (in Visual Studio 2010) that the lambda couldn't be converted to the type of WEIGHT_FUNC. I also know the answer: using std::function object:

typedef std::function<uint64_t (void*)>  WEIGHT_FUNC;

However, I also want to know how I can receive the type of lambda WITHOUT using std::function. What type should it be?

minjang
  • 8,860
  • 9
  • 42
  • 61
  • 2
    auto will just be useful to automatically determine the type, it's not a variant type, it can't be a parameter. – Klaim Jul 23 '10 at 18:41
  • 2
    Which compiler are you using? Seems your compiler is non-standard in regards to lambda's, they should be able to implicitly convert to a function pointer (in cases such as this.) – GManNickG Jul 23 '10 at 19:03
  • 2
    g++ 4.5 is fine with it, so i'm guessing VC10, for which i've already seen some lambda bugs. – Georg Fritzsche Jul 23 '10 at 19:24
  • 6
    [It's been fixed for the next release of Visual C++](https://connect.microsoft.com/VisualStudio/feedback/details/572138) – James McNellis Jul 23 '10 at 19:48
  • @James: Ah, of course you had a bug open for it - i should have known :) – Georg Fritzsche Jul 23 '10 at 19:51

3 Answers3

20

The conversion to function pointer is relatively new: It was introduced with N3043 on February 15, 2010.

While e.g. GCC 4.5 implements it, Visual Studio 10 was released on April 12, 2010 and thus just didn't implement it in time. As James pointed out, this will be fixed in future releases.

For the moment you have to use one of the alternative solutions provided here.

Technically something like the following workaround would work, but without variadic templates its no fun to generalize it (Boost.PP to the rescue...) and there is no safety net against passing capturing lambdas in:

typedef uint64_t (*WeightFunc)(void* param);

template<class Func> WeightFunc make_function_pointer(Func& f) {
    return lambda_wrapper<Func>::get_function_pointer(f);
}

template<class F> class lambda_wrapper {
    static F* func_;
    static uint64_t func(void* p) { return (*func_)(p); }    
    friend WeightFunc make_function_pointer<>(F& f);    
    static WeightFunc get_function_pointer(F& f) {
        if (!func_) func_ = new F(f);
        return func;
    }
};

template<class F> F* lambda_wrapper<F>::func_ = 0;

// ...
WeightFunc fp = make_function_pointer([](void* param) -> uint64_t { return 0; });
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • 8
    It's worth mentioning that the conversion to function pointers is only for stateless lambda functions, they can not capture lexical scope. – snk_kid Jul 24 '10 at 10:08
  • The conversion to function pointer seems not to work with g++ 4.5 in template code (http://tinyurl.com/3y6hkyq) – rafak Aug 06 '10 at 00:08
1

If you really insist on not using function<> then you could probably use decltype:

typedef decltype([](void*)->uint_64{return 0;}) my_lambda_type;

I really don't recommend this though since you're drastically limiting yourself and I don't even know if two lambda's with the same signature are guaranteed to be the same type.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • Is it guaranteed that the type generated will be the same than if you write the exact same typedef somewhere else? I don't think you should assume that the type is signature-dependent... but maybe i'm wrong. – Klaim Jul 23 '10 at 19:30
  • 1
    Old answer, I know, but lambda expression's cannot appear in an unevaluated context. (I think the rationale being what you brought up: since each lambda expression is a unique, unspecified type, you aren't guaranteed any particular meaningful answer an an unevaluated context.) – GManNickG Feb 04 '11 at 06:22
-1

Try with (not tested) :

#include <function>

typedef std::function< int64_t (void*) > weight_func;
typedef std::map<std::string, weight_func > CallbackTable;

I don't think there is any other way to do this than to use std::function or equivalent.

Klaim
  • 67,274
  • 36
  • 133
  • 188