2017-02-22 45 views
1
class A { 
    public: 
     int a; 
     char b; 
     double c; 
     A (int x, char y, double z) : a(x), b(y), c(z){} 
}; 

int main(){ 

    auto lambda = [](auto x) { 
     static auto y = x; 
     // y = x; 
     return y; 
    }; 

    int a = lambda(1); 
    char b = lambda('a'); 
    double c = lambda(1.5); 
    A  d = lambda(A(2, 'b', 2.5)); 

    return 0; 
} 

Этот код компилируется в Clang 3.8.0 и GCC 5.4.0 и отлично работает. Однако, принимая во внимание, что переменная y является static:Статическая автоматическая переменная в общей лямбда в C++ 14

  • Какой тип переменной y? Изменяется ли тип y при каждом вызове лямбда?
  • Является переменным y, инициализированным в каждом звонке, несмотря на то, что он static? Запрошенное задание // y = x не требуется для обновления значения переменной y.
  • Является ли это поведение стандартом C++ 14?

Если я печатаю sizeof(y) в каждом звонке, я получаю 4, 1, 8 и 16 соответственно.

On local and global static variables in C++

+2

родового Lambda в 'оператор (...)' более или менее * функция -template *. Следовательно, статические переменные будут созданы для каждого отдельного экземпляра функции. – WhiZTiM

ответ

4

Ваш лямбда родовое. Это означает, что это маскировка шаблона. Ситуация обрабатывается в соответствии с общими правилами для специализированных шаблонов.

Для каждого конкретного выведенного типа параметра x вы получаете отдельную специализацию своей функции. Итак, да для каждого конкретного типа x вы получаете отдельную копию y. Но основной механизм не так или иначе локализован на вашем static, это весь элемент вашей функции, который «копируется» для создания отдельной независимой реализации функции.

Каждая специализация вашей лямбды будет иметь отдельную копию y, которая будет инициализирована только один раз при первом вызове этой конкретной специализации.

ситуация практически эквивалентна более явном

template <typename T> void foo(T x) 
{ 
    static T y = x; 
    std::cout << y << std::endl; 
} 

int main() 
{ 
    foo(1); 
    foo('a'); 
    foo(1.5); 
    foo(3.0); 
} 

, который выводит 1, a, 1.5 и 1.5.

В этом примере вы получаете три независимые специализации foo: foo<int>, foo<char> и foo<double>. Каждая версия foo имеет свою собственную версию y, что означает, что в этом примере есть три разных статических y. Первый вызов каждой специализации инициализирует y, и последующие вызовы не будут повторно инициализировать его. В этом случае звонок в foo(1.5) инициализирует y для foo<double>, но последующий звонок foo(3.0) - нет.

То же самое происходит и в вашем случае, он просто использует другой синтаксис.

+0

Отлично! Это имеет смысл. Я также печатал адрес переменной 'y', и действительно, он был другим с вызовами лямбда с разными типами, и это был тот же адрес для вызовов с аргументами того же типа. Я знал о переменных «static», а также о шаблонах, но я не совсем понял это поведение. Теперь я делаю, большое спасибо! –

2

Lamda with auto - это не что иное, как класс с перегруженным оператором(), который является шаблоном, и использует auto для вывода типа (который следует правилам для вычитания параметра шаблона).

В этом случае у вас столько статических полей, сколько столько экземпляров этого оператора шаблона объекта функции.

Инициализация выполняются как в рукописном классе, который в первый раз функция срабатывает (лямбду в данном случае)