Почему нельзя использовать `decltype()` для `std::function` с помощью лямбды?

#c #templates #lambda

Вопрос:

мы знаем, что decltype() это может быть использовано для получения типа переменных, как показано ниже:

 int a = 0;
using a_t = decltype(a);
a_t b = -1; // it worked, and type of b is int
 

но это не сработало для этого:

 auto f = [](int a) -> int { return a   1;}; // the type of callable should be int(int)?

std::function<decltype(f)> F(f); // error
std::function<int(int)> G(f);    // worked
 

почему? и есть ли какой-либо метод для получения типа функции(в <> ) лямбда-выражения?

Комментарии:

1. отсутствует ; после a 1 и, пожалуйста, включите сообщение об ошибке в вопрос

2. тип лямбда-выражения не является типом функции , который требуется std::function .

3. для вывода типа функции лямбда-выражения можно использовать decltype(lambda::operator()) , за исключением того , что это универсальное лямбда-выражение.

4. С c 17 или более поздней версии вы можете это сделать std::function F(f); благодаря CTAD .

Ответ №1:

Это просто неправильное использование std::function оболочки. Этот тип предназначен для того, чтобы скрыть фактическую реализацию, обернув ее в объект, стираемый по типу, с как можно меньшим количеством информации о базовом вызываемом объекте: и это сигнатура функции.

При использовании вы decltype(f) получаете уникальный , созданный компилятором тип лямбда-выражения. Но это не то , как вы можете создать экземпляр a std::function , так как базовый, неспециализированный шаблон template<class> std::function не определен. Определена только специализация template<class R, class ...Args> std::function<R(Args...)> , и вы не можете создать ее экземпляр с типом лямбда-выражения.

Обратите внимание, что все лямбда-выражения также имеют подпись: они принимают некоторые аргументы (возможно, типы параметров шаблона) и возвращают значение определенного типа. Это информация, которую вам нужно ввести в создание std::function экземпляра. В вашем случае int(int) , как вы сами написали.

Ответ №2:

Существует ли какой-либо метод для получения типа функции (в <> ) лямбда-выражения?

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

 #include <functional>
#include <type_traits>

auto f = [](int a) -> int { return a   1;};

template <class F>
using fn_type_t = std::remove_pointer_t<decltype( std::declval<F>())>;

std::function<fn_type_t<decltype(f)>> F(f);
 

Godbolt.org

Унарный оператор запускает преобразование в int(*)(int) , а затем std::remove_pointer получает int(int) из типа этого выражения.