2

I have program I am writing that takes encrypted strings from a txt file and decrypts char by char. I am just gonna post the loop with which I am having the issue. Some notes about what is missing from code snippet:

Declaration and initialization of map<char,char> codes Declaration and opening of fstream inFile, loginFile Declaration of string userComp , passComp;

I have tried changing out the cout portions with loginFile << codes.at(c) The error says:

An enclosing-function local variable cannot be referenced in the lambda body unless it is in the capture list

However, I am unsure of the proper way and syntax needed to add to capture list.

This code works, but instead of printing to console, I need it to write to my loginFile

while (!inFile.eof())
        {
            getline(inFile, nameComp, ',');
            getline(inFile, passComp, '\n');


            for_each(nameComp.begin(), nameComp.end(), [codes](char c)
            {

                 cout << codes.at(c);
            });

            for_each(passComp.begin(), passComp.end(), [codes](char d)
            {
                cout << codes.at(d);
            });
            cout << endl;

        } 

I am looking for a specific solution involving the current code, but if there is a better way to achieve this I am open to changing my code.

Nellie Danielyan
  • 1,001
  • 7
  • 19
  • 3
    Unrelated: Fear the `while (!inFile.eof())`. [It is a bug!](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – user4581301 Apr 20 '19 at 21:18

1 Answers1

4

If you want to be able to in your lambda use something that lives outside of your lambda, you have to capture it. You can capture either just a reference to something or capture the value of something. The lambdas you have up there already capture codes by value in their capture list (the stuff between the […] at the beginning). If you want to use loginFile inside your lambda, you'll also have to capture that (that's what the error message is trying to tell you). Most likely, what you're looking for is

        for_each(nameComp.begin(), nameComp.end(), [&codes, &loginFile](char c)
        {
            loginFile << codes.at(c);
        });

or simply

        for_each(nameComp.begin(), nameComp.end(), [&](char c)
        {
            loginFile << codes.at(c);
        });

Note the use of &. This will capture the respective entities by reference rather than by value (I assumed that codes is some container which you will, most likely, also want to capture by reference instead of making a copy). The [&] in the second version specifies that anything you're using in the lambda should automatically be captured by reference (see, e.g., here for more on lambda captures). Note that capturing a reference means that your lambda now holds references to these object, so you have to make sure that the lambda will not outlive these objects or, at least, not be called anymore after the respective objects are gone…

Also, note that, instead of using std::for_each with a lambda, you might as well just use a range-based for loop (unless you're after the automatic parallelization that std::for_each can give you since C++17):

        for (char c : nameComp)
        {
            loginFile << codes.at(c);
        };
Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Yes that worked using ```&```! My question now is, why will it only work when capturing by reference? Also, where is a good resource for lambda usage with examples? I have a c++ book, but it does not even touch on the subject. – Misplaced Southerner Apr 20 '19 at 21:28
  • 1
    In your particular case, you were trying to capture `std::` stream objects, which are not copyable. Since they cannot be copied, attempting to capture them by value will fail. You would also not be able to pass them by value to a function. I'm afraid I don't really know a particular good resource for learning this topic. You may want to have a look here: https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11. Basically, lambda expressions are just syntax sugar for writing and instantiating an unnamed function object class on the spot… – Michael Kenzel Apr 20 '19 at 21:37