Чи гарантовано незаймана лямбда буде порожньою за стандартом?


12

Я шукаю спосіб ідентифікувати порожні (без захоплення) лямбда від інших лямбда в функції шаблону. Зараз я використовую C ++ 17, але мені цікаво і відповідей на C ++ 20.

Мій код виглядає приблизно так:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

Чи гарантується стандартом C ++ (17 або 20), що лямбда без захоплення, яка може бути конвертована у функціональний покажчик, також зробить std::is_emptyсправжній вихід?

Візьміть цей приклад як приклад:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

Живий приклад


2
Якщо ви дбаєте лише про лямбдаси без шаблону, ви можете використовувати SFINAE, щоб перевірити, чи +lambdaдобре сформовано перетворення у покажчик функції ( ).
HolyBlackCat

@HolyBlackCat Я думав про це, але, наскільки я пам’ятаю, MSVC цього не дозволяє, оскільки вони перевантажили оператора перетворення.
Гійом Ракікот

@GuillaumeRacicot MS відкриває окремий оператор перетворення для всіх доступних умов викликів. Просто виберіть один і спробуйте перетворити лямбда на порівняльний вказівник функції та перевірте, чи це успішно чи не вдається.
Ремі Лебо

+здається, працює тут .
HolyBlackCat

Відповіді:


13

Ні, насправді стандарт прямо передбачає дозвіл лямбдів мати розмір, який не відповідає їх декларації. [expr.prim.lambda.closure] / 2 стани

Тип закриття оголошується в області найменшого блоку, області класу або області простори імен, що містить відповідний лямбда-вираз. [Примітка. Це визначає набір просторів імен та класів, пов'язаних із типом закриття ([basic.lookup.argdep]). Типи параметрів лямбда-декларатора не впливають на ці пов'язані простори імен та класи. - кінцева примітка] Тип закриття не є агрегованим типом. Реалізація може визначати тип закриття інакше, ніж описано нижче, якщо це не змінює поведінку програми, яка спостерігається, крім зміни:

  • розмір та / або вирівнювання типу закриття,

  • чи тривірно копіюється тип закриття ([class.prop]), або (2.3)

  • чи є тип закриття класом стандартного макета ([class.prop]).

Реалізація не повинна додавати членів базового типу rvalue до типу закриття.

акцент мій

Таким чином, це дозволяє реалізувати лямбда члена, навіть якщо він не захоплює. Я не думаю, що будь-яка реалізація ніколи цього не зробила, але їм це дозволено законно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.