【问题标题】:Will C++0x support __stdcall or extern "C" capture-nothing lambdas?C++0x 是否支持 __stdcall 或 extern "C" capture-nothing lambdas?
【发布时间】:2010-05-29 13:18:00
【问题描述】:

昨天我在考虑是否可以利用 C++0x lambda 函数的便利性来为 Windows API 函数编写回调。

例如,如果我想将 lambda 用作 EnumChildProcEnumChildWindows 怎么办?比如:

EnumChildWindows(hTrayWnd, CALLBACK [](HWND hWnd, LPARAM lParam) {
        // ...
        return static_cast<BOOL>(TRUE); // continue enumerating
    }, reinterpret_cast<LPARAM>(&myData));

另一个用途是为 C 例程编写 extern "C" 回调。例如:

my_class *pRes = static_cast<my_class*>(bsearch(&key, myClassObjectsArr, myClassObjectsArr_size, sizeof(my_class), extern "C" [](const void *pV1, const void *pV2) {
        const my_class& o1 = *static_cast<const my_class*>(pV1);
        const my_class& o2 = *static_cast<const my_class*>(pV2);

        int res;
        // ...
        return res;
    }));

这可能吗?

我可以理解捕获变量的 lambda 永远不会与 C 兼容,但至少在我看来 capture-nothing lambda 可以兼容。

【问题讨论】:

  • 这在针对 C++11 标准的缺陷报告中得到了澄清,正如我在下面的回答中所解释的那样。

标签: c++ c lambda c++11


【解决方案1】:

没有捕获are implicitly convertible 指向函数指针的Lambdas(通过闭包类型定义的非显式转换函数)。

FCD似乎并没有指定那个函数指针类型的函数类型有什么语言链接,所以如果需要把这个函数指针传递给C函数,C++函数和C函数的调用约定需要一致.我相信在 Windows 上,情况确实如此。所以你应该能够将 lambda 传递给 Windows API 函数

typedef void(*callbackType)(void *userData);
extern "C" void someCFunction(callbackType callback);

int main() {
  someCFunction([](void *userData) { /* ... */ });
}

FCD 措辞5.1.2/6:

没有 lambda-capture 的 lambda 表达式的闭包类型有一个公共的非虚拟非显式 const 转换函数,指向具有与闭包类型的函数调用运算符相同的参数和返回类型的函数的指针。这个转换函数的返回值应该是一个函数的地址,当被调用时,它与调用闭包类型的函数调用运算符具有相同的效果。

我认为最终的标准应该有一个说明,说明有一个到 C 链接函数指针和 C++ 链接函数指针的转换函数,因为到 C 函数指针的转换是这个功能的目标之一。

【讨论】:

    【解决方案2】:

    函数指针的语言链接是由无捕获 lambda 转换产生的,在 C++11 标准中未指定,但在 defect report 1557 中已解决,其中说:

    5.1.2 [expr.prim.lambda] 第6段没有指定闭包类型的转换函数的函数类型的语言链接。

    解决方案是语言链接应该是 C++:

    没有 lambda 捕获的 lambda 表达式的闭包类型有一个公共的非虚拟非显式 const 转换函数,指向具有 C++ 语言链接的函数的指针 (7.5 [dcl.link])。具有与闭包类型的函数调用运算符相同的参数和返回类型。返回的值...

    我们可以在 C++14 标准草案中找到这种语言,因为状态是DRWP,这似乎不适用于 C++11。

    【讨论】:

    • 很棒的发现。但如果它是在 C++11 的生命周期中提出并接受的缺陷,那肯定意味着它肯定确实适用于 C++11?
    • @underscore_d 如果我们查看定义诸如DRWP 之类的术语的current active issues list 说:A DR issue whose resolution is reflected in the current Working Paper. The Working Paper is a draft for a future version of the Standard. 据我所知,这意味着它适用于 C++14 而不是 C ++11.
    【解决方案3】:

    没有什么特别好的理由不应该将其扩展到捕获 lambda。它需要一些动态代码生成,但它不应该超出编译器编写者的智慧,并且它会使与旧 C API 的互操作更容易几个数量级——不再需要通过无类型的 void*s 传递参数(这不是全部API 甚至提供)。

    【讨论】:

    • 问题不是动态代码生成,而是动态代码清理。您必须拥有语言级别的 GC 才能清理该代码。
    • 在 C++ 中没有其他任何东西。一个 thunk 的 shared_ptr 就足够了。
    猜你喜欢
    • 2019-12-22
    • 2010-11-15
    • 2011-06-09
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多