Сделать одну лямбду захвата

Это явно игрушечный пример, но допустим, у меня есть N функции как это:

void one(const int param) {
const auto func = [=](){ return 13 == param; };
}

void two(const int param) {
const auto func = [=](){ return 13 == param; };
}

И так далее; все они имеют идентичные лямбда захвата. Можно ли иметь 1 экземпляр лямбда, который всегда захватывает param функции, в которой он находится, а не N случаи? Может быть, в качестве дополнительного вопроса, который я должен задать, компилятор уже распознает репликацию и упростит их до одного экземпляра?

2

Решение

К сожалению, вы получите несколько типов с этим решением. [Expr.prim.lambda.closure] / 1 говорится, что

Тип лямбда-выражение (который также является типом объекта замыкания) является уникальный, безымянный тип несоединимого класса, называемый типом замыкания, свойства которого описаны ниже.

акцент мой

Так что каждый

const auto func = [=](){ return 13 == param; };

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

То, что вы могли бы сделать, это перевести повторение в функтор, и тогда у вас будет только один определенный класс.

class compare
{
int val;
public:
compare(int val) : val(val) {}
bool operator() const { return val = 13; }
};

и тогда ваши функции станут

void one(const int param) {
const auto func = compare{param};
}

void two(const int param) {
const auto func = compare{param};
}
3

Другие решения

Вы можете просто сделать функцию, которая возвращает лямбду:

auto make_lambda(int param) {
return [=](){ return 13 == param; };
}

bool one(const int param) {
return make_lambda(param)();
}

bool two(const int param) {
return make_lambda(param)();
}

Обе функции будут использовать один и тот же сгенерированный класс (но не один и тот же экземпляр). Это сгенерированный код (Получено с помощью C ++ Insights):

__lambda_2_12 make_lambda(int param)
{

class __lambda_2_12
{
public: inline /*constexpr */ bool operator()() const
{
return 13 == param;
}

private:
int param;

public: __lambda_2_12(int _param)
: param{_param}
{}

} __lambda_2_12{param};

return __lambda_2_12;
}bool one(const int param)
{
return make_lambda(param).operator()();
}bool two(const int param)
{
return make_lambda(param).operator()();
}
4

Синтезированный тип замыкания для лямбды является уникальным и определяется в точке определения, как указано в [expr.prim.lambda.capture]/2:

Тип замыкания объявляется в самой маленькой области блока, области класса или области пространства имен, которая содержит соответствующее лямбда-выражение […]

и захват параметра функции используется для создания нестатического члена данных для уникальный Тип замыкания введен в область действия функции: [expr.prim.lambda.capture]/10.2:

Для каждого объекта, захваченного копией, в типе замыкания объявляется неназванный элемент не статических данных. Порядок объявления этих членов не определен […]

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

2

Вы всегда будете отличаться типы, но вы можете не стать отчетливым код для каждого использования. Это работа для компоновщика. Линкер MSVC, а также экспериментальный gold компоновщик, выполните то, что MSVC называет «сворачивание КОМДАТА» (я не знаю, как это называет золото), которое идентифицирует идентичные функции внутри и между единицами перевода и объединяет их в одну.

1
По вопросам рекламы [email protected]