3

I'm having an issue where when I try to access a string that's the main param in a lambda, the compiler doesn't recognize it as so when I try to call functions using that string.

Here is my code:

void removePunctuation(std::vector<std::string> &inTokens,
                   std::vector<std::string> &outTokens) {
std::for_each(inTokens.begin(), inTokens.end(), [outTokens](std::string s) {
    std::string newS = s;
    // newS.erase(std::remove_if(newS.begin(), newS.end(), ispunct));
    outTokens.push_back(newS);});
}

And the following error is produced:

a2.cpp:114:19: error: no matching member function for call to 'push_back'
    outTokens.push_back(newS);});

I am also getting this sort of error in other functions, when I try to call a function that uses the lambda's string param in its call.

Any help is much appreciated!

Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49
  • 2
    Did you mean `std::for_each(inTokens.begin(), inTokens.end(), [&outTokens](const std::string& s) {std::string newS = s; outTokens.push_back(newS);});` – Simon Kraemer Oct 13 '16 at 16:16

4 Answers4

5

By default, lambda arguments are passed as read-only, try

[&outTokens](std::string s)

(It is perhaps what you want anyway, if the outTokens parameter is expected to be modified.)

Community
  • 1
  • 1
AlexD
  • 32,156
  • 3
  • 71
  • 65
2

Aside that you should capture outTokens by reference, std::transform suits this better:

outTokens.resize( inTokens.size() );
std::transform(inTokens.begin(), inTokens.end(), outTokens.begin(),
    [](std::string s) {
        s.erase(std::remove_if(s.begin(), s.end(), ispunct));
        return s;
    } );

If you pass std::string by value you do not need to create yet another copy to modify it and first parameter to removePunctuation should be const reference.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • However, now it seems to be erasing every single token that I end up printing. My call is as follows: while (getline(inFile, line)) { replaceHyphensWithSpaces(line); std::vector initialWords, words; splitLine(line, words); removePunctuation(initialWords, words); –  Oct 13 '16 at 17:09
  • I put there exact logic as you showed in your code, if you need it work different way create another question – Slava Oct 13 '16 at 21:34
1

You should capture outTokens by reference:

void removePunctuation(std::vector<std::string> &inTokens,
                   std::vector<std::string> &outTokens) {
    std::for_each(inTokens.begin(), inTokens.end(), [&outTokens](std::string s)
       {
           std::string newS = s;
           outTokens.push_back(newS);
       });
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

Variables captured by copy can't be modified, unless you make lambda mutable.

mutable - allows body to modify the parameters captured by copy, and to call their non-const member functions

Unless the keyword mutable was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside this operator().

e.g.

[outTokens](std::string s) mutable { ... }

But this means you'll modify on copy of outTokens, which might not be your intent. (Modify on a copy and then return doesn't make much sense.) You might want change it to capture by reference:

[&outTokens](std::string s) { ... }
Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405