C++0x lambda,如何作为参数传递?

17
请看下面的C++0x lambda相关代码:
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);
};

我在Visual Studio 2010中遇到了一个错误,错误提示lambda无法转换为WEIGHT_FUNC类型。我知道解决办法:使用std::function对象

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

不过,我也想知道如何在不使用std::function的情况下接收lambda的类型。应该使用什么类型?


2
auto 只是用于自动确定类型的工具,它不是一种变体类型,也不能作为参数。 - Klaim
2
你使用的是哪个编译器?看起来你的编译器在 lambda 方面不是标准的,它们应该能够在这种情况下隐式转换为函数指针。 - GManNickG
2
g++ 4.5可以正常运行,所以我猜测VC10也可以,不过我已经遇到了一些关于lambda表达式的bug。 - Georg Fritzsche
6
已经修复,将在下一个Visual C++版本中发布。 - James McNellis
@James: 哦,当然你已经为此问题创建了一个bug - 我应该知道的 :) - Georg Fritzsche
3个回答

20

将转换为函数指针相对较新:它是在2010年2月15日通过N3043引入的。

虽然例如GCC 4.5实现了它,但Visual Studio 10于2010年4月12日发布,因此没有及时实现它。正如James所指出的那样,这将在未来版本中得到修复

目前,您必须使用此处提供的替代解决方案之一。

从技术上讲,以下解决方法可能有效,但是没有可变参数模板,通用化就不好玩了(Boost.PP来拯救...),而且没有安全网来防止传递捕获lambda:

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

8
值得一提的是,将Lambda函数转换为函数指针仅适用于无状态Lambda函数,它们不能捕获词法范围。 - snk_kid
似乎在模板代码中,使用g ++ 4.5进行函数指针转换无法正常工作(http://tinyurl.com/3y6hkyq) - rafak

1

如果你真的坚持不使用 function<>,那么你可能可以使用 decltype:

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

我真的不建议这样做,因为这会严重限制你的能力,而且我甚至不知道两个具有相同签名的lambda是否保证是相同类型。


生成的类型是否保证与在其他地方编写完全相同的typedef生成的类型相同?我认为你不应该假设类型是签名相关的...但也许我错了。 - Klaim
1
旧答案,我知道,但是lambda表达式不能出现在未评估的上下文中。(我认为这样做的原因是您提出的:由于每个lambda表达式都是唯一的、未指定的类型,您不能保证在未评估的上下文中得到任何特定有意义的答案。) - GManNickG

-1

尝试使用(未经测试):

#include <function>

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

我认为除了使用std :: function或其等效物之外,没有其他方法可以做到这一点。


3
请使用std::function<R (T)>,而不是std::function<R (*)(T)> - Georg Fritzsche
我已经知道如何使用std::function来实现(请再次查看我的帖子)。我想知道是否有一种方法可以将lambda转换为函数指针,而不使用std::function。 - minjang
1
奇怪,我必须在VS2010中包含<functional>而不是<function>。 - Casebash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接