【问题标题】:Compiling lambda as Objective-C++ causes block cast将 lambda 编译为 Objective-C++ 会导致块转换
【发布时间】:2023-04-02 14:40:02
【问题描述】:

我有一个不可复制的 C++ lambda,它捕获了一个 unique_ptr,并且在使用 Apple Clang 作为 Objective-C++ 进行编译时的某些情况会导致 lambda 转换为块指针,此时由于尝试复制而导致编译失败的拉姆达。一个简单的例子如下:

int main(int argc, const char * argv[])
{   
    std::unique_ptr<int> myHeapInt = std::make_unique<int>(4);
    int myStackInt = 0;

    auto myLambda = [&, myHeapInt = std::move(myHeapInt)]()
    {
        myStackInt = *myHeapInt;
    };

    if(bool(myLambda)) //Error ar this point
    {
        *myHeapInt = 5;
    }

    std::invoke(myLambda);

    return 0;
}

错误如下:

Call to implicitly-deleted copy constructor of 'const lambda...
Implicit capture of lambda object due to conversion to block pointer here

有没有办法绕过这种转换?

【问题讨论】:

  • 为什么你认为你可以混合和匹配 C++ 和 Objective-C++?它们是不同的语言
  • Apparently you can,但这看起来像纯 c++。
  • 是的,我知道它们是不同的语言,我正在努力使两者都兼容。
  • Rajveer,混合两种语言不是一个好主意。使用“复制粘贴和调整”更容易制作和管理两个版本。 Dropbox 尝试为他们的移动应用程序编写基于 C++ 的代码(因此它可以在 iPhone 和 Android 上运行)并得出结论认为这是一个坏主意。现在他们只写了两个版本,一个是在 Kotlin 上为 Android 编写的,一个是为 Apple 编写的(使用它本机使用的任何语言...... Swift?)。
  • 将 C++ 与 Objective-C 混合使用非常好,这就是 Objective-C++ 的本质。

标签: clang clang++ objective-c++


【解决方案1】:

bool(myLambda) 是什么?我不知道。

使用 lambda 唯一能做的就是唤起它:myLambda()。你无法测试它是否存在或任何东西。

【讨论】:

  • 从技术上讲,您可以将 lambda 转换为 bool 如果 它没有捕获,因为它可以衰减为函数指针,然后可以转换为 bool。然而,这样做是没有意义的,因为你永远不可能有一个虚假的 lambda。
  • 我正在使用一个 std::function 替换 (github.com/Naios/function2),它曾经可以像 Objective-C++ 一样编译,但现在无法编译。此替换将 bool 转换作为某些优化的一部分,这是它现在失败的地方,因为 lambda 已转换为块。
  • 不幸的是,同样的结果,Clang 仍然尝试将其转换为块指针。
  • @Rajveer 我的意思不仅仅是 bool 演员,而是 if 完全。
【解决方案2】:

所以,我在这里并没有完全看到 Objective-C++ 的相关性,因为这段代码也不能编译为 C++:

objc++-noncopy-lambda.cpp:15:9: error: cannot convert '(lambda at objc++-noncopy-lambda.cpp:9:21)' to 'bool' without a conversion operator
    if (bool(myLambda))
        ^~~~~~~~~~~~~
1 error generated.

错误信息不同;我假设有一些尝试在 Objective-C++ 中将 lambda 隐式转换为块,我试图远离这样奇怪的边缘情况,但似乎在没有 operator bool 的情况下它可能会尝试转换为块首先。

无论哪种方式,您尝试编写的代码都没有任何意义,编译器会正确拒绝它。

我在 cmets 中看到您实际上正在尝试做一些不同的事情。您能否发布您实际尝试编写的代码的简化版本,据说可以编译为 C++ 但不是 Objective-C++?

【讨论】:

  • 你的环境是什么,你有什么编译选项?我的示例在使用 Clang 编译为 C++17 时运行良好,并且实际库在 MSVC、Clang 和 GCC(也编译为 C++17)上编译良好。创建简化版本并不容易,因为它是一个模板化的头文件类,这就是我创建上面示例的原因,因为这正是失败的部分。本质上,该类实现了一个 vtable,如果可调用实现 operator bool() 或可以转换为 bool,它会对其进行优化。
  • 无论如何我发现这是在 Clang 中设计的,以便块和 lambda 可以互操作 (clang.llvm.org/docs/…) 所以我决定在编译为 Objective-C++ 时禁用此优化。
【解决方案3】:

我试图将 std::function (github.com/Naios/function2) 的模板化头文件类替换编译为 Objective-C++,它实现了一个 vtable 并在可调用实现 operator bool() 时对其进行优化,或者可以转换为布尔值。

最后,如果编译为 Objective-C++,我只是决定禁用此优化,因为转换为块指针是 Clang 设计的,以实现块 lambda 互操作性 (http://clang.llvm.org/docs/LanguageExtensions.html#interoperability-with-c-11-lambdas)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多