0

I am a c++ newbie so I'm not sure how to write this, but basically I want a function that takes in a few parameters and returns a function pointer that does not need any parameters and can be executed for later use. Exactly like a closure.

I know c++ does not have closures, but can get some of the same effects with lambda expessions. I'm just not sure if it can do what I want it to do. Again I don't know much c++. I have been going through tutorials and reading posts about how lambdas work in c++, but I can't figure out how do get this code to work.

Here is some example code of what I'm trying to in typescript

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

This is what I want in c++, but it's wrong

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

And here is what I have in c++, works, but cannot take in parameter

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

I appreciate any responses in advance!

Nick Ruha
  • 45
  • 2
  • 7
  • 1
    You say that you "don't know much c++". Unfortunately, the very first thing you will learn about C++ is that it is not about instant gratification. It takes time to learn it, a long time. You are describing one of the basic templates from the C++ library, but to get there it's necessary to study, and learn, core C++ fundamentals, for about a year or two, before reaching its advanced topics, like templates. Any attempt to short-circuit the process will, eventually, always end in tears. C++ is just too complicated to be learned by asking one question at a time, on Stackoverflow. – Sam Varshavchik Nov 23 '22 at 15:17
  • You were already close. You only have to transfer the parameter values into the closure. Just insert a `=` in the lambda introducer, so that it reads `[=]() {`... Of course, you also have to get the parameter syntax right, but that is really the topic of an introductory C++ tutorial. – j6t Nov 23 '22 at 15:30
  • @SamVarshavchik I would like to disagree. It might take some years to get C++ to the "professional software developer level", but you only need a little bit of that knowledge to actually get something done. And anyone with some programming experience should be able to get to a pretty good understanding of the language it in a matter of a few months. Perhaps instead of wasting your time demotivating people willing to learn you should instead actually tell them what "basic templates from the C++ library" they are "describing"?! – Nikita Demodov Nov 23 '22 at 15:31
  • Here's the problem, @NikitaDemodov: this is what's going to happen with the "little bit of that knowledge to actually get something done". You now get excited, and copy/paste the given answer and use it (I'm referring to YSC's answer). Great. You're excited. You're happy. You're so excited that you decided that you want to call the lambda a second time. Nothing happens. No error. Nothing. You tear your hair out. Finally, a day later, at your wits' ends, you resort to posting another question on Stackoverflow. Contrast that: you take time to learn C++ up front, then you just see why and fix it. – Sam Varshavchik Nov 23 '22 at 16:00
  • @SamVarshavchik I do totally agree with your sentiment. C++ - as most complicated things - needs a good foundation to really get going. And in this case the OP should definitely take a look at some introductory C++ tutorials. However, I found your comment to be discouraging of actually pursuing these fundamentals. It makes C++ sound like some dark whichcraft that only stereotypical neckbeards have a chance at using. Yet C++ is widely used by many people who have never programmed in their life (take Arduino-newbies as an example!). I want to motivate OP to read a tutorial - not start a degree. – Nikita Demodov Nov 23 '22 at 20:16
  • The OP won't be motivated to invest time into reading a textbook or a good tutorial, @NikitaDemodov, as long as the OP still believes that asking one question at a time is a good way to learn C++ fundamentals. – Sam Varshavchik Nov 23 '22 at 21:10

2 Answers2

0

Before answering the technical question, a note from Sam Varshavchik I agree with:

You say that you "don't know much c++". Unfortunately, the very first thing you will learn about C++ is that it is not about instant gratification. It takes time to learn it, a long time. You are describing one of the basic templates from the C++ library, but to get there it's necessary to study, and learn, core C++ fundamentals, for about a year or two, before reaching its advanced topics, like templates. Any attempt to short-circuit the process will, eventually, always end in tears. C++ is just too complicated to be learned by asking one question at a time, on Stackoverflow.

Now for the technical question: you can acheive simple closures as described here with lambda captures1:

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

Live demo


1)

The captures is a comma-separated list of zero or more captures, optionally beginning with the capture-default. The capture list defines the outside variables that are accessible from within the lambda function body. The only capture defaults are

& (implicitly capture the used automatic variables by reference) and = (implicitly capture the used automatic variables by copy). The current object (*this) can be implicitly captured if either capture default is present. If implicitly captured, it is always captured by reference, even if the capture default is =. The implicit capture of *this when the capture default is = is deprecated. (since C++20)

YSC
  • 38,212
  • 9
  • 96
  • 149
  • You might wander where that `-->` _"goes to"_ comes from. This is a joke explained in [this other question](https://stackoverflow.com/q/1642028/5470596). – YSC Nov 23 '22 at 15:43
0
std::function<void(param1: T, param2: P, param3: V)> (*myVariable)() = myClosure;

I'm not rly sure what's going on in here. my wild guess would be you want to do something like this

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

but if you just want to store function for later use you can actually either

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

or

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

both lambda version and binding version should be cast-able to std::function<void()>