2016-04-19 9 views
5

To dziwny błąd dla mnie. Sprawdź poniższy kod:Brak pasującego błędu funkcji elementu wewnątrz wyrażenia lambda?

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

Pierwszy push_back metoda zdała kompilację ale drugi nie powiodła się, w wyniku czego otrzymuje błąd:

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

Nota kompilator:

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

Ale metoda nie jest oznaczona const**.
Cóż, nie używam żadnego argumentu const i nie mogę określić, co kompilator chce mi powiedzieć. Czy ktokolwiek mógłby mi pomóc?

Odpowiedz

10

Domyślnie funkcje operatora połączenia Lambda to const. Jeśli chcesz zmienny operator call, powiedzmy mutable:

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

Mając const być siły domyślne, aby być wyraźnie o tym, że masz na myśli uchwycić kopię wektora i mutować tę kopię, zamiast oryginalny wektor v.

Natomiast zmienne, które są wychwytywane przez odniesienie mogą być zmutowane przez funkcje składowe const kwalifikowaną:

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

(to w zasadzie dlatego const T jest taka sama jak T gdy T = U &; nie ma „referencje stałe . "w C++)

+1

Prawdopodobnie chcesz przechwycić także przez odniesienie. – NathanOliver

+3

@NathanOliver: Nie "tak dobrze", ale raczej "zamiast". –

+0

Ah tak. Zamiast tego rzeczywiście – NathanOliver

4

uchwycenia przez wartość jest const użyć słowa kluczowego mutable (nie zmienia oryginalny wektor):

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

lub przez odniesienie (zmienia oryginalny wektor):

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

powodu tagu C++14 i dla kompletności wywodu, chciałbym przytoczyć również listę initializer jako alternatywne rozwiązanie:

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

Jeśli chcesz uchwycić przez kopię zamiast przez odniesienie:

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

Listy inicjalizacyjne jako (powiedzmy) metoda przechwytywania są dostępne od C++14, jak już wspomniano.