如何保存函数指针以供以后在 c++ 中使用,具有保存状态的类似闭包

How do I save a function pointer for later use in c++, similar closures that have a saved state

提问人:Nick Ruha 提问时间:11/23/2022 更新时间:11/23/2022 访问量:47

问:

我是一个 c++ 新手,所以我不确定如何写这个,但基本上我想要一个函数,它接受一些参数并返回一个不需要任何参数的函数指针,可以执行以供以后使用。就像一个闭合。

我知道 c++ 没有闭包,但可以通过 lambda expessions 获得一些相同的效果。我只是不确定它是否能做我想让它做的事情。同样,我对 c++ 了解不多。我一直在阅读有关 lambdas 如何在 c++ 中工作的文章和文章,但我不知道如何让这段代码工作。

这是我尝试在打字稿中执行的一些示例代码

let myVariable;

const myClosure = (param1: number, param2: number, param3, string, ) => {
    return () => {
        // Do something with params
        console.log(param1, param2, param3);
    }
}

function whereInitalized() {
    myVariable = myClosure(1,2,"name");

}

function whereExecuted() {
    myVariable(); // prints the params
}

whereInitalized();
whereExecuted();

这是我在 c++ 中想要的,但这是错误的

// Not correct syntax or type
// Having trouble getting typing for this variable;
std::function<void(param1: T, param2: P, param3: V)> (*myVariable)() = myClosure;

std::function<void()> myClosure(param1: T, param2: P, param3: V) {
    return []() { // Returns a function that does not take a parameter
        param1.someMethod();
        param2->Call(blah, blah);
        // ... More work
        
    };
}

void functionWhereInitalized() {
    myVariable = myClosure(param1, param2, param3);
}

void functionWhereExecuted() {
    myVariable();
}

这是我在 c++ 中拥有的东西,有效,但不能接受参数

std::function<void()> myVariable = myClosure;

std::function<void()> myClosure() {
    return [num = 99]() mutable {
        // Test code to see it gets called
        num++; 
        std::cout << num << "  --  " << "\n";
    };
}

void functionWhereInitalized() {
    myVariable = myClosure();
}


void functionWhereExecuted() {
    myVariable();
}

我感谢提前的任何回复!

C++ 闭包 函数指针

评论

1赞 Sam Varshavchik 11/23/2022
你说你“不太懂 c++”。不幸的是,您将了解C++的第一件事是它与即时满足无关。学习它需要时间,很长一段时间。您正在描述 C++ 库中的基本模板之一,但要达到目的,有必要学习和学习核心 C++ 基础知识大约一两年,然后才能达到其高级主题,如模板。任何试图缩短这一过程的尝试最终都会以眼泪告终。C++太复杂了,不能通过在Stackoverflow上一次问一个问题来学习。
0赞 j6t 11/23/2022
你已经很接近了。您只需将参数值传输到闭包中即可。只需在 lambda 介绍器中插入 a,即可读取 ...当然,您还必须正确使用参数语法,但这确实是 C++ 入门教程的主题。=[=]() {
0赞 Nikita Demodov 11/23/2022
@SamVarshavchik 我想不同意。将C++提升到“专业软件开发人员水平”可能需要几年时间,但你只需要一点点知识就可以真正完成一些事情。任何有一定编程经验的人都应该能够在几个月内对这门语言有很好的理解。也许与其浪费时间去激励愿意学习的人,不如告诉他们他们正在“描述”什么“来自C++库的基本模板”?!
0赞 Sam Varshavchik 11/24/2022
@NikitaDemodov,问题来了:这就是“真正完成某事的一点点知识”将要发生的事情。你现在很兴奋,复制/粘贴给定的答案并使用它(我指的是 YSC 的答案)。伟大。你很兴奋。你很开心。你非常兴奋,以至于你决定要第二次调用 lambda。什么也没发生。没有错误。无。你把头发扯掉。最后,一天后,在你无计可施的情况下,你求助于在 Stackoverflow 上发布另一个问题。相比之下:你花时间预先学习C++,然后你只是看到原因并修复它。
0赞 Nikita Demodov 11/24/2022
@SamVarshavchik 我完全同意你的观点。C++ - 就像最复杂的事情一样 - 需要一个良好的基础才能真正开始。在这种情况下,OP绝对应该看看一些介绍性的C++教程。但是,我发现您的评论令人沮丧,无法真正追求这些基本原理。它使C++听起来像是一些黑暗的工艺,只有刻板的颈胡子才有机会使用。然而,C++被许多一生中从未编程过的人广泛使用(以Arduino新手为例!我想激励 OP 阅读教程 - 而不是开始学位。

答:

0赞 YSC 11/23/2022 #1

在回答技术问题之前,我同意 Sam Varshavchik 的一句话:

你说你“不太懂 c++”。不幸的是,您将了解C++的第一件事是它与即时满足无关。学习它需要时间,很长一段时间。您正在描述 C++ 库中的基本模板之一,但要达到目的,有必要学习和学习核心 C++ 基础知识大约一两年,然后才能达到其高级主题,如模板。任何试图缩短这一过程的尝试最终都会以眼泪告终。C++太复杂了,不能通过在Stackoverflow上一次问一个问题来学习。

现在是技术问题:您可以使用 lambda 捕获1 实现简单的闭包,如下所述:

#include <iostream>
#include <string_view>

auto make_closure(std::ostream& out, std::string_view message, int repeat=1)
{
    return [&out,repeat,message]() mutable { while (repeat --> 0) out << message; };
}

int main(){
    auto say_hello = make_closure(std::cout, "Hello\n", 2);
    say_hello();
}

现场演示


1)

捕获是以逗号分隔的零个或多个捕获列表,可以选择以 capture-default 开头。捕获列表定义可从 lambda 函数体中访问的外部变量。唯一的捕获默认值是

&(通过引用隐式捕获使用的自动变量)和(通过复制隐式捕获使用的自动变量)。 如果存在任一捕获默认值,则可以隐式捕获当前对象 ()。如果隐式捕获,则始终通过引用捕获它,即使捕获默认值为 。不推荐使用捕获默认值的隐式捕获。(从 C++ 20 开始)=*this=*this=

评论

0赞 YSC 11/23/2022
你可能会徘徊在那个“去”的地方。这是另一个问题中解释的一个笑话。-->
0赞 Oleh Kostiv 11/23/2022 #2
std::function<void(param1: T, param2: P, param3: V)> (*myVariable)() = myClosure;

我不确定这里发生了什么。我的疯狂猜测是你想做这样的事情

std::function<void()> yourClosure(T1 const& p1, T2 const& p2, T3 const& p3)
{
  return [p1, p2, p3]() { /* do the thing */};
}

但是,如果您只想存储函数以供以后使用,您实际上可以

auto const function = [a,b,c](){ /* meaningful code*/ };

some_types... a, b, c; // whatever variables you have
auto const function_with_params = [](auto const& a, auto const& b, auto const&c){ /* skrnyr dgdyr */};
auto const function_with_bound_params = std::bind(function_with_params, a, b, c);

lambda 版本和绑定版本都应该可以强制转换为std::function<void()>