Сделайте одну лямбду захвата - PullRequest
0 голосов
/ 27 сентября 2018

Это, очевидно, игрушечный пример, но допустим, у меня есть 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 экземпляров?Может быть, в качестве дополнительного вопроса, который я должен задать, компилятор уже распознает репликацию и упростит ее до одного экземпляра?

Ответы [ 4 ]

0 голосов
/ 28 сентября 2018

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

0 голосов
/ 28 сентября 2018

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

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

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

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

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

0 голосов
/ 28 сентября 2018

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

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()();
}
0 голосов
/ 28 сентября 2018

К сожалению, вы получите несколько типов с этим решением. [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};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...