LINUX.ORG.RU

История изменений

Исправление rumgot, (текущая версия) :

А неявные преобразования зло

Нет. Неявные неожиданные преобразования зло. А ожидаемые и желаемые - нет.

Неправильно ты ответил. Лямбда это всегда функтор. В твоём случае происходит неявное преобразование

Да. Признаю. Перечитал стандарт.

Просто когда нет захвата, он реализует метод как статический метод класса

А вот тут ты наврал.

C++17 Draft N4659 8.1.5.1 Closure types
The closure type for a non-generic lambda-expression with no lambda-capture has a conversion function to
pointer to function with C ++ language linkage (10.5) having the same parameter and return types as the
closure type’s function call operator.

Итого исправленный комментарий:

#include <functional>
#include <iostream>

using namespace std;

class Functor {
   public:
    Functor(){};
    void operator()() { cout << "Functor::operator()" << endl; }
};

void caller(void (*fp)()) { fp(); }

template <typename F>
void callerTemplate(F f) {
    f();
}

int main() {
    // Здесь можно присвоить лямбда-выражение указателю на функцию (или передать в качестве указателя
    // на функцию в другую функцию) потому что лямбда без списка захвата (в этом случае лямбда реализована
    // компилятором как функтор у которого есть функция преобразования в указатель на функцию с такой же сигнатурой вызова, что и
    // оператор вызова operator() данного функтора и поэтому данную лямбду можно привести к указателю на функцию):
    void (*p0)() = []() { cout << "Lambda without capture list called" << endl; };  // Ok
    caller([]() { cout << "Lambda without capture list called" << endl; });         // Ok

    int i{};
    // А в случае, когда лямбда имеет список захвата, компилятор реализует ее как функтор без функции
    // преобразования в указатель на функцию (который уже нельзя привести к указателю  на функцию):
    // void (*p1)() = [i]() { cout << "Lambda with capture list called " << i << endl; };  // Ошибка компиляции
    // caller([i]() { cout << "Lambda with capture list called " << i << endl; });         // Ошибка компиляции
    // caller(Functor());                                                                  // Ошибка компиляции

    // В случае использования шаблонов, один шаблон может принимать функциональные сущности разных типов
    // (разумеется для каждого типа будет инстанцирован свой экземпляр шаблона):
    callerTemplate([i]() { cout << "Lambda with capture list called " << i << endl; });
    callerTemplate(Functor());
}

Исправление rumgot, :

А неявные преобразования зло

Нет. Неявные неожиданные преобразования зло. А ожидаемые и желаемые - нет.

Неправильно ты ответил. Лямбда это всегда функтор. В твоём случае происходит неявное преобразование

Да. Признаю. Перечитал стандарт.

C++17 Draft N4659 8.1.5.1 Closure types
The closure type for a non-generic lambda-expression with no lambda-capture has a conversion function to
pointer to function with C ++ language linkage (10.5) having the same parameter and return types as the
closure type’s function call operator.

Итого исправленный комментарий:

#include <functional>
#include <iostream>

using namespace std;

class Functor {
   public:
    Functor(){};
    void operator()() { cout << "Functor::operator()" << endl; }
};

void caller(void (*fp)()) { fp(); }

template <typename F>
void callerTemplate(F f) {
    f();
}

int main() {
    // Здесь можно присвоить лямбда-выражение указателю на функцию (или передать в качестве указателя
    // на функцию в другую функцию) потому что лямбда без списка захвата (в этом случае лямбда реализована
    // компилятором как функтор у которого есть функция преобразования в указатель на функцию с такой же сигнатурой вызова, что и
    // оператор вызова operator() данного функтора и поэтому данную лямбду можно привести к указателю на функцию):
    void (*p0)() = []() { cout << "Lambda without capture list called" << endl; };  // Ok
    caller([]() { cout << "Lambda without capture list called" << endl; });         // Ok

    int i{};
    // А в случае, когда лямбда имеет список захвата, компилятор реализует ее как функтор без функции
    // преобразования в указатель на функцию (который уже нельзя привести к указателю  на функцию):
    // void (*p1)() = [i]() { cout << "Lambda with capture list called " << i << endl; };  // Ошибка компиляции
    // caller([i]() { cout << "Lambda with capture list called " << i << endl; });         // Ошибка компиляции
    // caller(Functor());                                                                  // Ошибка компиляции

    // В случае использования шаблонов, один шаблон может принимать функциональные сущности разных типов
    // (разумеется для каждого типа будет инстанцирован свой экземпляр шаблона):
    callerTemplate([i]() { cout << "Lambda with capture list called " << i << endl; });
    callerTemplate(Functor());
}

Исходная версия rumgot, :

А неявные преобразования зло

Нет. Неявные неожиданные преобразования зло. А ожидаемые и желаемые - нет.

Неправильно ты ответил. Лямбда это всегда функтор. В твоём случае происходит неявное преобразование

Да. Признаю. Перечитал стандарт.

C++17 Draft N4659 8.1.5.1 Closure types
The closure type for a non-generic lambda-expression with no lambda-capture has a conversion function to
pointer to function with C ++ language linkage (10.5) having the same parameter and return types as the
closure type’s function call operator.