C ++: заставить экземпляры lamba иметь уникальные статические переменные - PullRequest
7 голосов
/ 04 июня 2019

Я хотел бы создать функцию, которая генерирует лямбды, в которой каждая из лямбд имеет свою статическую переменную. Однако, вопреки тому, что я думал, статические переменные, похоже, будут разделены между экземплярами. Например,

#include <iostream>

auto make_lambda(){
    return [](){
        static auto count = 0;
        return count++;
    };
}

int main() {
    auto a = make_lambda();
    auto b = make_lambda();
    std::cout << &a << ", " << a() << std::endl;
    std::cout << &b << ", " << b() << std::endl;
}

возвращает

0x7ffc229178df, 0
0x7ffc229178de, 1

Так что a и b кажутся уникальными экземплярами, но разделяют этот статический счет. Я думал, что увижу и действительно хочу увидеть что-то вроде

0x7ffc229178df, 0
0x7ffc229178de, 0

живая демоверсия

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

Ответы [ 3 ]

11 голосов
/ 04 июня 2019

Отключите статическую переменную и используйте расширенный лямбда-захват:

#include <iostream>

auto make_lambda(){
    return [count = 0]() mutable {
        return count++;
    };
}

Если вы хотите, чтобы разные лямбда-экземпляры обменивались состоянием со своими соответствующими копиями, но не между ними, вы можете вместо этого использовать std::shared_ptr:

auto make_lambda(){
    return [count = std::make_shared<int>(0)]() mutable {
        return (*count)++;
    };
}
6 голосов
/ 04 июня 2019

Вы можете использовать тот факт, что для созданных экземпляров функций и шаблонных сущностей, которые они включают, есть свои собственные копии статических переменных, определенных в функции.Превращение make_lambda в шаблон ...

template<int>
static auto make_lambda(){
    return [](){
        static auto count = 0;
        return count++;
    };
}

... создаст новую статическую переменную для каждого нового аргумента шаблона, уникальную для TU (поскольку сам шаблон функции равен static):

auto a = make_lambda<0>();
auto b = make_lambda<1>();
std::cout << &a << ", " << a() << std::endl;
std::cout << &b << ", " << b() << std::endl;

Это не совсем тот синтаксис, который вы хотели, но он выполняет свою работу.Если вы не возражаете против использования препроцессора и, возможно, расширений компилятора, вы можете получить простой синтаксис вызова функции с помощью вспомогательного макроса.

#define make_lambda() make_lambda<__COUNTER__>()

где __COUNTER__ - расширение GCC, которое расширяется до нового числакаждый раз требуется расширение в любом отдельном TU.

3 голосов
/ 04 июня 2019

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

auto make_lambda(){
    int count = 0;
    return [count]() mutable {
        return count++;
    };
}
...