5

This is quite a strange error to me. Check the code below:

void test(void){
    vector<string> v;
    v.push_back("hello");
    auto fn=[=](){
        v.push_back("world");
    };
}

The first push_back method passed the compilation but the second failed, yielding the error:

Error:no matching member function for call to 'push_back'

The compiler note is:

**Note:(687, 36) candidate function not viable: 'this' argument has type 'const vector' (aka 'const vector, allocator > >')

But the method is not marked const**.
Well I am not using any const argument and I cannot figure what the compiler is trying to tell me. Could anybody help me?

3 Answers 3

10

Lambda call operator member functions are const by default. If you want a mutable call operator, say mutable:

auto fn = [=]() mutable {
//              ^^^^^^^
    v.push_back("world");
};

Having const be the default forces you to be explicit about the fact that you mean to capture a copy of the vector and mutate that copy, rather than the original vector v.

By contrast, variables that are captured by reference can be mutated by const-qualified member functions:

auto fn = [&]() {
//        ^^^
    v.push_back("world");  // modifies original "V"!
};

(This is essentially because const T is the same as T when T = U &; there are no "constant references" in C++.)

Sign up to request clarification or add additional context in comments.

5 Comments

Probably want to capture by reference as well.
@NathanOliver: Not "as well", but rather "instead".
Ah yes. Instead indeed
Well what is it mean that you want to "capture a copy and mutate that copy, rather than the original v"? I tested this using mutate, add a line of code that each time i call that lambda function, i print &v out, and seems that the address of that two "copies" are the same?
@Heranort: Compare it with the address of the very first vector v in your code.
4

capture by value is const use the keyword mutable (doesn't change the original vector):

auto fn = [=]() mutable {
    v.push_back("world");
};

or by reference (changes the original vector):

auto fn = [&]() {
    v.push_back("world");
};

Comments

0

Because of the C++14 tag and for the sake of completeness, I'd cite also the initializer list as an alternative solution:

[&vec = v](){ vec.push_back("world") };

If you want to capture by copy instead of by reference:

[vec = v]() mutable { vec.push_back("world") };

Initializer lists as a (let me say) capture method are available since C++14, as already mentioned.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.