为什么 C++ Lambda 和 IOS 块不是完全关联的?

问题描述 投票:0回答:1

我是 IOS 编程新手,正在学习块和 lambda。在我对块和 C++ lambda 的研究中,我读到 lambda 本质上可以替换块,因为它们可以做几乎相同的事情。 除了 capture 子句和 C++ 特定(可变和抛出)可选关键字之外,情况似乎如此。我发现了一些可能会产生影响的差异 - 但不确定。 我可以创建一个 std::function 包装类型变量 (lambda) 并分配一个块及其等效的 lambda 语句。 但是,如果我创建一个块类型变量并尝试为其分配一个 lambda - 编译会因错误而终止。为什么?我将在下面显示代码和错误输出。 另外,我不能 typedef lambda,我必须使用 std::function 包装函数类型来执行等效操作。为什么?


#include <iostream>
#include <functional>
#include <pthread.h>
#include <xpc/xpc.h>
#include <dispatch/dispatch.h>

#define SHOW_COMPILE_ERROR
// add comments on next line to see the compile error
#undef SHOW_COMPILE_ERROR


// You cannot create a lambda typedef, but you can create a general purpose
// polymorphic function wrapper from std::wrapper
// e.g. typedef  [] (xpc_object_t) -> void do_custom_message_l_t; is not legal
// but the std::function declaration is legal - why?
typedef std::function<void(xpc_object_t)> do_custom_msg_l_t;
// block typedefs are legal as below
typedef void (^do_custom_msg_b_t)(xpc_object_t);

// create a function declaration with a callback using either
// approaches - the block typedef or the std::function wrapper
// just as well
xpc_object_t build_message(int func,
                           do_custom_msg_b_t&);
xpc_object_t build_message(int func,
                           do_custom_msg_l_t&);

// create a couple of global variables of the block or std::function type
do_custom_msg_b_t do_custom_msg_b;
do_custom_msg_l_t do_custom_msg_l, do_custom_msg_l2;

#if defined(SHOW_COMPILE_ERROR)
do_custom_msg_b_t do_custom_msg_b2;
#endif

int main(int argc, char *argv[])
{
    // assign a block to the block type global
    do_custom_msg_b = ^(xpc_object_t custom_message) {
        auto p= xpc_copy_description(custom_message);
        std::cerr << "Custom Message Objects: " << p << std::endl;
        free(p);
    };

    // assign a std::function type a lambda definition - cool.
    // but change the variable to do_custom_msg_b and suddenly there
    // is an error!  So you can assign a lambda definition to a block
    // variable type.  Very weird.
    do_custom_msg_l = [] (xpc_object_t custom_message) {
        auto p= xpc_copy_description(custom_message);
        std::cerr << "Custom Message Objects: " << p << std::endl;
        free(p);
    };

#if defined(SHOW_COMPILE_ERROR)
    // this is not legal - why?, if it is legal to assign a block to a lambda
    // /std::function then why not the other way around?
    do_custom_msg_b2 = [] (xpc_object_t custom_message) {
        auto p= xpc_copy_description(custom_message);
        std::cerr << "Custom Message Objects: " << p << std::endl;
        free(p);
    };
#endif

    // we are now assigning a block to std::function wrapper (lambda)
    // this works just fine . . . weird!
    do_custom_msg_l2  = ^(xpc_object_t custom_message) {
        auto p= xpc_copy_description(custom_message);
        std::cerr << "Custom Message Objects From Blocks Assigned to std::function: " << p << std::endl;
        free(p);
    };

    // in conclusion blocks can be assigned lambda/std::functions but std::functions/lambdas
    // cannot be assigned to block types (typedefs).  So there is a false equivilence between
    // lambdas and blocks

    // here is how lambdas are normally defined and executing them
    // is very easy
    auto mylambda = [] (void *ptr){
        std::cout << "This lambda " << ptr << " is running in thread " << pthread_self() << std::endl;
        sleep(1);
    };
    // here is the block equivalent to the above lambda
    void (^myblock) (void) = ^{
        std::cout << "This block is running in thread " <<  pthread_self() << std::endl;
        sleep(1);
    };
    // call that lambda with its address as a parameter
    mylambda(&mylambda);
    // call the block
    myblock();
    // dispatch the lambda - cool!
    dispatch_async_f(dispatch_get_main_queue(), &mylambda, mylambda);
    // dispatch the block - very cool!
    dispatch_async(dispatch_get_main_queue(), myblock);
    // build an object using the block callback
    xpc_object_t msg = build_message(1, do_custom_msg_b);
    // build a message utilizing the lambda call
    msg = build_message(2, do_custom_msg_l);
    // call the lambda variable that was assigned a block
    // this works - very cool!
    msg = build_message(3, do_custom_msg_l2);
#if defined(SHOW_COMPILE_ERROR)
    // nope, this won't even build
    msg = build_message(4, do_custom_msg_b2);
#endif
    dispatch_main();
    return 0;
}


/**
 * @brief build a new message header to be sent to the server
 * @param func The function id of what command to be sent
 * @param do_custom_msg block that can optionally customize this created message
 * @returns the xpc object built
 * @note objects created with this function must be released
 */
xpc_object_t build_message(int func,
                           do_custom_msg_b_t& do_custom_msg)
{
    xpc_object_t msg = xpc_dictionary_create_empty();
    xpc_dictionary_set_uint64(msg, "typ", func);
    xpc_dictionary_set_date(msg, "date", time(nullptr));
    xpc_dictionary_set_uint64(msg, "serno",
                              1);
    if(nullptr != do_custom_msg)
    {
        do_custom_msg(msg);
    }
    return msg;
}

/**
 * @brief build a new message header to be sent to the server
 * @param func The function id of what command to be sent
 * @param do_custom_msg block that can optionally customize this created message
 * @returns the xpc object built
 * @note objects created with this function must be released
 */
xpc_object_t build_message(int func,
                           do_custom_msg_l_t& do_custom_message )
{
    xpc_object_t msg = xpc_dictionary_create_empty();
    xpc_dictionary_set_uint64(msg, "typ", func);
    xpc_dictionary_set_date(msg, "date", time(nullptr));
    xpc_dictionary_set_uint64(msg, "serno",
                              1);
    if(nullptr != do_custom_message)
    {
        do_custom_message(msg);
    }
    return msg;
}

以下是我的环境的详细信息: CLion 2024.1.4。 苹果铿锵版本15.0.0 运行 Sonoma 14.6.1 的 2023 Mac Studio 这是错误消息:

/Applications/CLion.app/Contents/bin/cmake/mac/aarch64/bin/cmake --build "/Users/marksanderson/Projects/codeing tests/cmake-build-debug" --target codeing_tests -j 22
[1/2] Building CXX object CMakeFiles/codeing_tests.dir/main.cpp.o
FAILED: CMakeFiles/codeing_tests.dir/main.cpp.o 
/Library/Developer/CommandLineTools/usr/bin/c++   -g -std=gnu++20 -arch arm64 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -fcolor-diagnostics -MD -MT CMakeFiles/codeing_tests.dir/main.cpp.o -MF CMakeFiles/codeing_tests.dir/main.cpp.o.d -o CMakeFiles/codeing_tests.dir/main.cpp.o -c '/Users/marksanderson/Projects/codeing tests/main.cpp'
/Users/marksanderson/Projects/codeing tests/main.cpp:59:24: error: assigning to 'do_custom_msg_b_t' (aka 'void (^)(xpc_object_t)') from incompatible type '(lambda at /Users/marksanderson/Projects/codeing tests/main.cpp:59:24)'
    do_custom_msg_b2 = [] (xpc_object_t custom_message) {
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
ninja: build stopped: subcommand failed.
c++ ios clang
1个回答
0
投票

AppleClang 代码块不是标准 C++ 的功能,并且与函数指针不同,该语言没有定义将 lambda 转换为代码块的规则。

如果 SDK 需要代码块,则您必须使用代码块。这种情况很简单,只需将

[]
替换为
^

即可
do_custom_msg_b2 = ^(xpc_object_t custom_message) {
    auto p= xpc_copy_description(custom_message);
    std::cerr << "Custom Message Objects: " << p << std::endl;
    free(p);
};
© www.soinside.com 2019 - 2024. All rights reserved.