可以“类型”吗? lambda 表达式的表达方式?

发布于 2024-09-26 09:18:20 字数 523 浏览 2 评论 0原文

将 lambda 表达式视为可调用对象的“语法糖”,是否可以表达未命名的基础类型?

一个例子:

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;

Thinking of lambda expressions as 'syntactic sugar' for callable objects, can the unnamed underlying type be expressed?

An example:

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

Now, [](int l, int r) { return l > r; } is an elegant replacement for the above code (plus the necessary creation of callable objects of gt), but is there a way to express gt (the type) itself?

A simple usage:

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

疾风者 2024-10-03 09:18:20

不,你不能将它放入 decltype 因为

lambda 表达式不得出现在未计算的操作数中

尽管您可以执行以下操作

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

,但这确实很难看。请注意,每个 lambda 表达式都会创建一个新的唯一类型。如果之后您在其他地方执行以下操作,t 的类型与 s 不同,

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

您可以在此处使用 std::function,但请注意,这会产生一点点运行时成本,因为它需要间接调用 lambda 函数对象调用运算符。它在这里可能可以忽略不计,但如果您想以这种方式将函数对象传递给 std::sort 例如,它可能很重要。

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

一如既往,先编码,然后分析:)

No, you cannot put it into decltype because

A lambda-expression shall not appear in an unevaluated operand

You can do the following though

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

But that is really ugly. Note that each lambda expression creates a new unique type. If afterwards you do the following somewhere else, t has a different type than s

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

You can use std::function here, but note that this will incur a tiny bit of runtime cost because it needs an indirect call to the lambda function object call operator. It's probably negligible here, but may be significant if you want to pass function objects this way to std::sort for example.

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

As always, first code then profile :)

海夕 2024-10-03 09:18:20

直接回答你的问题:不。

你需要使用可以从任何类型(类似于具有明确定义类型的函子)分配的东西。一个例子是 std::function,如 sbi 的答案所示。然而,这不是 lambda 表达式的类型。

Direct answer to your question: No.

You'll need to use something that is assignable from any type resembling a functor that has a well defined type. One example is std::function as shown in sbi's answer. That isn't, however, the type of the lambda expression.

故人爱我别走 2024-10-03 09:18:20

从 C++ 20 开始,不带捕获的 lambda 是默认可构造的,因此可以简单地将 lambda 内联的 decltype 作为第二个模板参数传递给 std::set

std::set<int, decltype([](int l, int r){return l > r;})> s2;

当然,在这种颠倒自然顺序的特定情况下,std::greater 更合适。

std::set<int, std::greater<>> s2;

Since C++ 20, lambdas without captures are default constructible, so one can simply pass decltype of the lambda inline as the second template parameter to std::set.

std::set<int, decltype([](int l, int r){return l > r;})> s2;

Of course, in this specific case of reversing the natural order, std::greater is more appropriate.

std::set<int, std::greater<>> s2;
溺深海 2024-10-03 09:18:20

您可以使用一个小类 lambda_wrapper<> 以低成本包装 lambda。它比 std::function 快得多,因为没有虚函数调用和动态内存分配。
包装器通过推导 lambda 参数列表和返回类型来工作。

#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;
}

You could use a small class lambda_wrapper<>, to wrap a lambda at low costs. Its much more faster than std::function because there are no virtual function call and a dynamic memory alloc.
Wrapper works by deducing the lambda arguments list and return type.

#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;
}
我不是你的备胎 2024-10-03 09:18:20

至少在 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);

In Microsoft Visual Studio at least (I haven't tried this with other compilers), and if you don't capture anything, the type seems to be a regular function pointer:

std::string (*myFunctionPointer)(int x) = [] (int x) {
  char buffer[10];
  return std::string("Test ") + itoa(x, buffer, 10);
};
std::string testOutput = myFunctionPointer(123);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文