Можно ли выразить «тип» лямбда-выражения? - PullRequest
51 голосов
/ 06 октября 2010

Считая лямбда-выражения «синтаксическим сахаром» для вызываемых объектов, можно ли выразить безымянный базовый тип?

Пример:

struct gt {
    bool operator() (int l, int r) {
        return l > r;
    }
} ;

Теперь [](int l, int r) { return l > r; } - это элегантная замена вышеприведенного кода (плюс необходимое создание вызываемых объектов gt), но есть ли способ выразить сам gt (тип)?

Простое использование:

std::set<int, gt> s1;  // A reversed-order std::set
// Is there a way to do the same using a lambda?
std::set<int, some-magic-here-maybe([](int l, int r) { return l > r; }) > s2;

Ответы [ 4 ]

59 голосов
/ 06 октября 2010

Нет, вы не можете поместить его в decltype, потому что

Лямбда-выражение не должно появляться в неоцененном операнде

Вы можете сделать следующее, хотя

auto n = [](int l, int r) { return l > r; };
std::set<int, decltype(n)> s(n);

Но это действительно ужасно. Обратите внимание, что каждое лямбда-выражение создает новый уникальный тип. Если впоследствии вы делаете следующее где-то еще, t имеет тип, отличный от s

auto n = [](int l, int r) { return l > r; };
std::set<int, decltype(n)> t(n);

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

std::set<int, function<bool(int, int)>> s([](int l, int r) { return l > r; });

Как всегда, сначала код, затем профиль:)

1 голос
/ 06 октября 2010

Прямой ответ на ваш вопрос: Нет.

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

0 голосов
/ 26 апреля 2018

По крайней мере в Microsoft Visual Studio (я не пробовал это с другими компиляторами), и если вы ничего не захватываете, тип выглядит как обычный указатель на функцию:

std::string (*myFunctionPointer)(int x) = [] (int x) {
  char buffer[10];
  return std::string("Test ") + itoa(x, buffer, 10);
};
std::string testOutput = myFunctionPointer(123);
0 голосов
/ 21 июля 2017

Вы можете использовать небольшой класс lambda_wrapper <>, чтобы обернуть лямбду при низких затратах.Это намного быстрее, чем std :: function, потому что нет вызова виртуальной функции и динамического выделения памяти.Оболочка работает, выводя список аргументов лямбда и возвращаемый тип.

#include <iostream>
#include <functional>
#include <set>

template <typename T, typename ... Args>
struct lambda_wrapper : public lambda_wrapper<decltype(&T::operator())(Args...)> {};

template <typename L>
struct lambda_wrapper<L> {
private:
    L lambda;

public:
    lambda_wrapper(const L & obj) : lambda(obj) {}

    template<typename... Args>
    typename std::result_of<L(Args...)>::type operator()(Args... a) {
        return this->lambda.operator()(std::forward<Args>(a)...);
    }

    template<typename... Args> typename
    std::result_of<const L(Args...)>::type operator()(Args... a) const {
        return this->lambda.operator()(std::forward<Args>(a)...);
    }
};
template <typename T>
auto make_lambda_wrapper(T&&t) {
    return lambda_wrapper<T>(std::forward<T>(t));
}
int main(int argc, char ** argv) 
{
    auto func = make_lambda_wrapper([](int y, int x) -> bool { return x>y; });
    std::set<int, decltype(func)> ss(func);
    std::cout << func(2, 4) << std::endl;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...