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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3867276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:55:57  来源:igfitidea点击:

Can the 'type' of a lambda expression be expressed?

c++stllambdac++11

提问by Yehoshafat Hashiloni

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

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

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?

现在,[](int l, int r) { return l > r; }是对上述代码的优雅替代(加上必要的 gt 可调用对象的创建),但是有没有办法表达 gt(类型)本身?

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;

回答by Johannes Schaub - litb

No, you cannot put it into decltypebecause

不,你不能把它放进去,decltype因为

A lambda-expression shall not appear in an unevaluated operand

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

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, thas a different type than s

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

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

You can use std::functionhere, 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::sortfor example.

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

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

As always, first code then profile :)

与往常一样,首先编写代码,然后配置文件 :)

回答by Edward Strange

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.

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

回答by barney

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.

您可以使用小类 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;
}

回答by Alexander Hugestrand

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:

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