2017-01-24 13 views
1

Интересно, почему я могу использовать глобальные переменные (спасибо Крису Drew для коррекции меня) в lamdas и почему мне не нужно, чтобы захватить их:Доступ к переменным в лямбда без списка захвата

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

size_t i = 0; 
vector<int> v = {1,2,3}; 

int main() 
{ 
    auto lambda = [](){i = v.size();}; 
    lambda(); 
    cout << i << endl; 

    return EXIT_SUCCESS; 
} 

В этом минимум рабочий пример Я обращаюсь к size_t и вектору, не захватывая их. Я должен был бы, если бы они были объявлены внутри основного метода. Почему это так и как я могу скопировать size_t и вектор? Я попытался использовать [=] в качестве списка захвата, но он не копирует v и i.

+5

они являются глобальными переменными –

+0

Возможные Дубликат: [Lambda с пустым списком захвата все еще в состоянии захватить объекты из глобальной области?] (http://stackoverflow.com/questions/34398564/lambda-with-empty-capture-list-still-able-to-capture-objects-from-global-scope/34398671#34398671) – NathanOliver

+0

Пожалуйста, будьте более конкретными, чем «не работает». Отправьте программу, которая «не работает», и объясните, что с ней не так. – molbdnilo

ответ

3

Один из способов захвата глобальной переменной величиной является использование C++ 14 generalized lambda captures:

#include <iostream> 
#include <vector> 

size_t i = 0; 
std::vector<int> v = {1,2,3}; 

int main() { 
    auto lambda = [myi = i, myv = v]()mutable{myi = myv.size();}; 
    lambda(); 
    std::cout << i << std::endl; 
} 

Live demo.

2

В вашем случае i и v являются глобальной переменной, доступной для всего ТУ.

Как вы спросили, как их захватить по значению, я думаю, вы должны уловить их, используя как [=], так и перечисляя переменные [i, v], но это приведет к ошибке, поскольку они будут доступны только для чтения, и вы назначая i внутри лямбда-тела.

Вариант 1:
захвата I по реф и V по значению (если это имеет смысл вообще ...):

#include <iostream> 
#include <vector> 
using namespace std; 
int main() { 
    size_t i = 0; 
    vector<int> v = {1,2,3}; 
    auto lambda = [&i,v](){i = v.size();}; 
    lambda(); 
    cout << i << endl; 

    return EXIT_SUCCESS; } 

http://ideone.com/fkn4za

Вариант 2:
использовать изменяемую лямбду и захватывать как по значению (это делает еще меньше смысла).
I.e. see this question on SO.
Пожалуйста, обратите внимание, что в этом случае также i будет захвачен значением, таким образом, глобальный i не будет назначен, оставаясь при значении == 0.

http://ideone.com/qwlFVv

+0

И как его скопировать? Использование '[=]' в качестве списка захвата не работает – Bambino

+0

См. Дополнение к ответу. Не совсем понятно, почему вы хотите захватить их (оба) по стоимости. – roalz

+0

Я ожидал увидеть нулевую печать, потому что я не использую глобальные переменные, так как я пытаюсь их скопировать. – Bambino

2

Лямбда имеет обращается к глобальным переменным и статическому переменные в классе без их явного захвата. Если бы это была локальная переменная, то программа была бы плохо сформирована.

#include <iostream> 
#include <vector> 
using namespace std; 
int main() 
{ 
    size_t i = 0; 
    vector<int> v = {1,2,3}; 
    auto lambda = [](){i = v.size();}; //Error, 
    lambda(); 
    cout << i << endl; 

    return EXIT_SUCCESS; 
} 

Как видно here

же со статическими переменными в классе:

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

struct S{ 
    void touch(){ []{ k = 89; }(); } 
    static int getK(){ return k; } 
private: 
    static int k; 
}; 

int S::k = 0; 


int main() 
{ 
    S s; 
    std::cout << S::getK() << std::endl; 
    s.touch(); 
    std::cout << S::getK() << std::endl; 
} 

Как видно Here

+0

Я знаю. Я просто использовал неправильный термин для описания вектора и size_t. Интересно, как я могу скопировать size_t и вектор? Использование '[=]' в качестве списка захвата не работает. – Bambino

+0

Если вы захватили локальную переменную и вам нужно изменить локальный захват, вам нужно использовать 'mutable' lambda – WhiZTiM

+0

Использование mutable, похоже, работает при использовании локальных переменных. Но использование его с глобальными переменными дает исходный результат. – Bambino

2

Ваш лямбда в основном преобразуется в функтор, это то же самое, как:

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

size_t i = 0; 
vector<int> v = {1,2,3}; 

struct lambda 
{ 
    void operator()() { i = v.size(); } 
}; 

int main() 
{ 
    lambda x; 
    x(); 
    cout << i << endl; 

    return EXIT_SUCCESS; 
} 

Как вы можете видеть, lambda может прекрасно получить доступ к любой глобальной переменной, даже в их имени, переменная глобально доступна.

Если i и v были местными для main(), тогда у нас была бы проблема, и нам пришлось бы их захватить.

+0

Спасибо, ядро ​​моего вопроса, хотя я не очень хорошо это сказал, должен был спросить, как я могу скопировать вектор и size_t. Кажется, я должен просто скопировать их с помощью new size_t и vector. – Bambino

+0

@ Bambino Да, вы можете скопировать их внутри лямбды, а затем работать над этими переменными. –