лямбды в неоцененном контексте (до C ++ 20) - PullRequest
3 голосов
/ 17 апреля 2019

Я сейчас читаю P0315R1 газету, в которой говорится о лямбдах в неоцененных контекстах

В документе есть утверждение, объясняющее , почему лямбды не могут появляться в неоцененных контекстах (конечно, только до C ++ 20) , как показано ниже:

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

Может кто-нибудь объяснить это утверждение на примере?

Ответы [ 2 ]

5 голосов
/ 18 апреля 2019

Немного предыстории: компоновщики не понимают перегрузку функций - они понимают только имена функций, как в языке Си. Вот почему компиляторы C ++ манипулируют именами ваших функций. void foo(int) становится _Z3fooi. Искаженное имя кодирует типы всех аргументов. Если ваша функция возникла в результате создания шаблона, все аргументы шаблона также будут закодированы. Если они сами являются шаблонными классами, их аргументы шаблона кодируются и т. Д. Рекурсивно, пока не будут достигнуты примитивные типы, такие как int или указатели на функции.

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

auto foo() { return [](){}; }
auto bar() { return [](){}; }

foo и bar возвращают различные типы. Если вы затем передадите их в другой шаблон функции, имя этого шаблона будет искажено, как если бы оно было foo::__lambda1 или что-то в этом роде.

Если лямбды появятся в decltype, это нарушит этот механизм.

void bar(decltype([](){}));
void bar(decltype([](){})) {}

Это прототип и определение? Или это две разные перегрузки bar? Как идентифицировать их по единицам перевода (как искажать названия)?

До сих пор C ++ запрещал даже задавать этот вопрос. Документ, на который вы ссылаетесь, дает ответ: такие вещи не могут иметь связи. Даже не пытайтесь их калечить.

0 голосов
/ 25 апреля 2019

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

Таким образом, в конце компоновщик не может объединить эти множественные определения «одной и той же» функции, потому что искаженные имена различаются.

...