Вывод типа лямбда выражения c параметром по умолчанию
1,00
р.
р.
Без использования опции -Wpedantic компилятор с поддержкой c++11 разрешает использовать в лямбда-выражениях значение по умолчанию. Для такого выражения можно использовать тип std::function с указанием типов всех параметров, в том числе и тех, что указаны по умолчанию. Однако, используя автоматический вывод типов с указанием ключевого слова auto, лямбда выражение получает специфичный тип, например, main()::, где значения в круглых скобках - типы параметров, передаваемых в это выражение. И эти значения указываются всегда вне зависимости от того, есть ли у них значение по умолчанию (что в общем-то и логично). Ниже привожу пример кода. #include #include void f1(std::function lambda) { if (lambda) { std::cout << lambda() << std::endl } }<br>void f2(std::function lambda) { if (lambda) { std::cout << lambda(1) << std::endl } }<br>int main() { auto lambda1 = [](int a = 3) -> int { return a } f1(lambda1) f2(lambda1) std::function lambda2 = []() { return 1 } std::function lambda3 = [](int a) { return a } f1(lambda2) //f2(lambda2) // Очевидно несоответствие типов //f1(lambda3) // Очевидно несоответствие типов f2(lambda3) } В примере кода тип main():: приводится к std::function. Мне не хватает знаний для понимания, почему компилятор не ругается на несоответствие типов. Прошу помощи в объяснении. И связанные вопросы. Могу ли я явно указать тип, подобный тому, что выводится автоматически? Могу ли я указать компилятору, чтобы он запрещал подобное приведение типов?
Ответ Тип объекта замыкания (closure object), порождаемого лямбда-выражением, никак не зависит от параметров лямбды и не определяется ими. Наличие или отсутствие аргументов по умолчанию здесь никакой роли не играет. Каждое лямбда-выражение порождает новый уникальный тип - это все, что вам нужно знать о типе объекта замыкания. Даже если два лямбда-выражения полностью идентичны, они все равно получат никак не связанные друг с другом уникальные типы. То, что в вашем примере во внутреннем имени этого типа вы увидели какой-то намек на список параметров - не более чем косметическая особенность используемой вами реализации. При этом то текстовое описание типа объекта замыкания, который вы видите в сообщениях компилятора, не является исчерпывающим описанием фактического типа. Например, в ответ на auto f1 = [](){} auto f2 = [](){} &f1 == &f2 вы получите от GCC диагностическое сообщение вида error: comparison between distinct pointer types 'main()::*' and 'main()::*' lacks a cast Как видите, описания типов в кавычках совершенно идентичны. Тем не менее это разные, никак не связанные друг с другом типы. Так что при работе с лямбда-выражениями никакой речи о "соответствии типов" не может быть вообще: все типы объектов замыкания уникальны и никогда ничему не соответствуют. почему компилятор не ругается на несоответствие типов Класс std::function<> построен на принципах type erasure, т.е. фактически является более узкоспециализированным аналогом std::any. Конструктор этого класса является шаблонным (см. номер 5 здесь) - в нем вообще нет и быть не может никакой проверки "соответствия типов" на уровне базовой системы типов языка. На уровне базовой системы типов языка этот конструктор может принимать на вход абсолютно любые типы. А какие-либо проверки навешиваются на этот конструктор уже на уровне библиотечной реализации, через техники вроде SFINAE. При инициализации вида std::function sf = f проверяется требование Callable: объект f должен быть Callable в качестве функции типа F. Проверка этого требования и работает в вашем примере. Например, объект замыкания lambda1 является Callable и как int() и как int(int). Поэтому вы можете использовать его и для инициализации std::function, и для инициализации std::function. Могу ли я явно указать тип, подобный тому, что выводится автоматически? Явно - нет. Тип объекта замыкания определяется реализацией и синтаксиса для его явного указания не существует. "Указать" его вы можете только неявно после того, как он уже вывелся - через применение decltype к уже существующему объекту замыкания auto f1 = [](){} decltype(f1) f2 = f1 Могу ли я указать компилятору, чтобы он запрещал подобное приведение типов? Компилятор здесь ни при чем. Вы имеете дело с чисто библиотечной функциональностью: реализацией std::function<>. Пока вы пользуетесь классом std::function<>, он будет вести себя как того требует спецификация языка.