Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I capture some (but not all) member variables of a class with C++ lambda

Tags:

c++

The following dummy example may not really make sense in real world. But it explains the question. I have a class Foo with members firstname and lastname. The function ForEachMessage takes a lambda. I want it to capture only the firstname of Foo but not lastname. How do I achieve that?

#include <iostream>
#include <vector>
#include <functional>
using namespace std;

vector<string> messagesList;
void ForEachMessage(function<void(const string&)>callBack)
{
    for (const auto& str : messagesList) {
        callBack(str);
    }
}

class Foo {
public:
    std::string firstname;
    std::string lastname;
    void say() {
        ForEachMessage([this](const std::string& someMessage)
        {
            cout << firstname << ": " <<  someMessage << endl;
        });

        // Error: firstname in capture list doesn't name a variable
        // ForEachMessage([firstname](const std::string& someMessage)
        // {
        //    cout << firstname << ": " <<  someMessage << endl;
        // });

        // Error: expect ',' or ']' in lambda capture list
        // ForEachMessage([this->firstname](const std::string& someMessage)
        // {
        //    cout << firstname << ": " <<  someMessage << endl;
        // });
    }
};

int main(int argc, const char * argv[]) {
    Foo foo;
    foo.firstname = "Yuchen";
    foo.lastname = "Zhong";
    messagesList.push_back("Hello, World!");
    messagesList.push_back("Byebye, World!");
    foo.say();
    return 0;
}
like image 582
Yuchen Avatar asked Mar 01 '16 17:03

Yuchen


2 Answers

You can use the C++14 named capture for this:

ForEachMessage([bla=firstname](const std::string& someMessage)
    {
        cout << bla << ": " <<  someMessage << endl;
    });

(See it live) To avoid a copy, you may also capture by reference with [&bla=firstname] instead. For a discussion on how to capture by const&, see this question and in particular this answer.

(Remark: The local name can, but need not be different from the member name.)

like image 60
Baum mit Augen Avatar answered Oct 26 '22 23:10

Baum mit Augen


Create a reference to firstname

const std::string& rfn = firstname;

And capture the reference

ForEachMessage([rfn](const std::string& someMessage)
{
  cout << rfn << ": " << someMessage << endl;
}
like image 39
Nard Avatar answered Oct 26 '22 23:10

Nard