Як працює родова лямбда на C ++ 14?


114

Як працює загальна лямбда ( autoключове слово як тип аргументу) у стандарті C ++ 14?

Це на основі шаблонів C ++, де компілятор кожного типу аргументів генерує нову функцію з тим самим тілом, але замінені типи (поліморфізм часу компіляції) або він більше схожий на загальну інформацію Java (тип стирання)?

Приклад коду:

auto glambda = [](auto a) { return a; };

6
Виправлено на C ++ 14, спочатку використовувався C ++ 11, про який йде мова
sasha.sochka

Відповіді:


130

Родові лямбди були введені в Росії C++14.

Просто тип закриття, визначений лямбда-виразом, матиме оператор шаблонного виклику, а не звичайний оператор виклику без шаблону C++11lmbdas (звичайно, коли він autoз'являється принаймні один раз у списку параметрів).

Тож ваш приклад:

auto glambda = [] (auto a) { return a; };

Зробимо glambdaпримірник цього типу:

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

Пункт 5.1.2 / 5 стандартної чернетки n3690 C ++ 14 визначає, як визначається оператор виклику типу закриття заданого лямбда-виразу:

Тип закриття для негенерального лямбда-виразу має оператор виклику функції загальної вбудованої функції (13.5.4), параметри якого і тип повернення описуються відповідно параграфом-декларацією параметра-вираз лямбда-виразу та типом зворотного повернення. Для загальної лямбда, тип закриття має загальнодоступний шаблон учасника оператора виклику функції вбудованого (14.5.2), список шаблонів-параметрів якого складається з одного винайденого типу шаблону-параметра для кожного виникнення автоматичного в пункті-декларації-лямбда-декларації, за порядком зовнішності. Винайдений тип шаблону-параметра є пакетом параметрів, якщо відповідна декларація параметра оголошує пакет параметрів функції (8.3.5). Тип повернення та параметри функції шаблону оператора виклику функції виводяться із затримки типу "лямбда-вираз" та "зворотного типу" та "декларування параметрів", замінюючи кожне виникнення авто в специфікаторах decl для декларування параметру-декларації параметра на ім'я відповідний винайдений шаблон-параметр.

Нарешті:

Це схоже на шаблони, коли для кожного компілятора різних типів аргументів генеруються функції з тим самим тілом, але змінені типи, або він більше схожий на дженерики Java?

Як пояснено у вищевказаному абзаці, загальні лямбда - це лише синтаксичний цукор для унікальних безіменних функторів із шаблоновим оператором виклику. Це має відповісти на ваше запитання :)


7
Однак вони також дозволяють локально визначений клас методом шаблону. Що нового.
Якк - Адам Невраумон

2
@Yakk: Хіба вже не було обмеження для локальних функціональних шаблонів із C ++ 11?
Себастьян Мах

2
@phresnel: Ні, це обмеження не було знято
Енді Проул

1
@AndyProwl: Я усвідомлюю свою помилку. Те, що було скасовано, використовувало місцеві типи як аргументи шаблону (як в int main () { struct X {}; std::vector<X> x; })
Себастьян Мах,

1
@phresnel: Правильно, це дійсно змінилося
Енді Проул

25

На жаль , вони не входять до C ++ 11 ( http://ideone.com/NsqYuq ):

auto glambda = [](auto a) { return a; };

int main() {}

З g ++ 4,7:

prog.cpp:1:24: error: parameter declared auto
...

Однак спосіб його впровадження в C ++ 14 відповідно до пропозиції Портленда щодо загальних лямбдаз :

[](const& x, & y){ return x + y; }

Це призведе до більшої частини звичайного створення анонімного класу функторів, але за відсутності типів компілятор випустить шаблонного члена- operator():

struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};

Або відповідно до нової пропозиції Пропозиція для загальних (поліморфних) лямбдаських виразів

auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;

Так, так, для кожної перестановки параметрів виникає нова інстанція, однак, члени цього функтора все одно поділяться (тобто захоплені аргументи).


6
Ця пропозиція дозволити скидання специфікатора типу є абсолютно гротескною.
Гонки легкості по орбіті

Вони зайшли з g ++ - 4,9 . Вам потрібно поставити -std=c++1y.
emsr

Я не розумів, що у Ideone ще немає gcc-4.9 та C ++ 14.
emsr

питання: чи autoмає це ті ж правила відрахування, що і класичне авто? Якщо ми посилаємось на шаблонну аналогію, це означатиме, що авто не є автором, це ті ж правила, що і відрахування типу шаблону. Тоді виникає питання: чи відрахування шаблону еквівалентно auto?
v.oddou

@ v.oddou: "Класичний авто" - це добре. Для мене "класичне автоматичне" означає "Змінна стека", і колись він використовувався на відміну від staticабо register:) У будь-якому разі, так, використання autoтам означає, що під кришкою формується звичайний шаблон. Насправді лямбда буде замінено компілятором внутрішньо класом функторів, а autoпараметр означає, що template <T> ... (T ...)буде випромінюватися.
Себастьян Мах

17

Це запропонована функція C ++ 14 (не в C ++ 11), схожа (або навіть еквівалентна) шаблонам. Наприклад, N3559 надає такий приклад:

Наприклад, цей загальний лямбда-вираз, що містить висловлювання:

auto L = [](const auto& x, auto& y){ return x + y; };

це може призвести до створення типу закриття та об'єкта, який веде себе подібним до структури нижче:

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.