简体   繁体   English

c ++ 11 / 1y lambda函数的类型签名是什么?

[英]what is the type signature of a c++11/1y lambda function?

I was wondering if there is a standard way to get the type signature (ie the return type and the types) of its parameters of any given lambda? 我想知道是否有一种标准方法来获取任何给定lambda参数的类型签名(即返回类型和类型)?

The reason I ask is that I've always wondered what exactly is the type auto in the declaration like auto l =[](int x,int y)->int{return x+y;} . 我想问的原因是,我一直想知道到底是什么类型auto像声明auto l =[](int x,int y)->int{return x+y;} In other use cases of auto , it's a convenience and shorter alternative for a longer type name. auto其他用例中,对于较长的类型名称,这是一种方便且较短的替代方法。 But for lambdas, is there even an alternative way to declare the lambda variable? 但是对于lambda,甚至还有另一种方法来声明lambda变量吗?

My understanding is that a standard lambda is nothing more than a function object, and it is its own type. 我的理解是,标准的lambda仅仅是一个函数对象,而是它自己的类型。 So, even if two lambdas have the same return type and parameter types, they are still two different, unrelated classes/functors. 因此,即使两个lambda具有相同的返回类型和参数类型,它们仍然是两个不同的,不相关的类/函数。 But this there a way to capture the fact that they are the same in terms of type signature? 但这有没有办法捕捉到它们在类型签名方面相同的事实?

I think the type signature I am looking for can be something like a std::function<> object of the correct types. 我认为我要寻找的类型签名可以是正确类型的std::function<>对象。

A more useful/involved question is, if it's possible to extract the type signature, this is possible to write a general wrapper function to convert any lambda function to a std::function object of the same type signature. 一个更有用/更有意义的问题是,如果可以提取类型签名,则可以编写一个通用包装函数,以将任何lambda函数转换为具有相同类型签名的std::function对象。

According to Can the 'type' of a lambda expression be expressed? 根据可以表达lambda表达式的“类型”吗? , there is actually a simple way in current c++ (without needing c++1y) to figure out the return_type and parameter types of a lambda. ,实际上,当前c ++中有一种简单的方法(不需要c ++ 1y)来找出lambda的return_type和参数类型。 Adapting this, it is not difficult to assemble a std::function typed signature type (called f_type below) for each lambda. 为此,为每个lambda组装一个std::function类型的签名类型(以下称为f_type )并不困难。

I. With this abstract type, it is actually possible to have an alternative way to auto for expressing the type signature of a lambda, namely function_traits<..>::f_type below. I.使用这种抽象类型,实际上可能有一种auto方式来表示lambda的类型签名,即下面的function_traits<..>::f_type Note: the f_type is not the real type of a lambda, but rather a summary of a lambda's type signature in functional terms. 注意: f_type不是lambda的实际类型,而是功能上lambda类型签名的摘要。 It is however, probably more useful than the real type of a lambda because every single lambda is its own type . 但是,它可能比lambda的实际类型有用,因为每个lambda都是自己的类型

As shown in the code below, just like one can use vector<int>::iterator_type i = v.begin() , one can also do function_traits<lambda>::f_type f = lambda , which is an alternative to the mysterious auto . 如下代码所示,就像可以使用vector<int>::iterator_type i = v.begin() ,也可以执行function_traits<lambda>::f_type f = lambda ,这是神秘auto的替代品。 Of course, this similarity is only formal. 当然,这种相似只是形式上的。 The code below involves converting the lambda to a std::function with the cost of type erasure on construction of std::function object and a small cost for making indirect call through the std::function object. 下面的代码包括将拉姆达转换为std::function上的结构类型擦除的成本std::function对象和用于通过使间接调用小成本std::function对象。 But these implementation issues for using std::function aside (which I don't believe are fundamental and should stand forever), it is possible, after all, to explicitly express the (abstract) type signature of any given lambda. 但是,除了使用std::function之外,这些实现问题(我不认为这是基本的,应该永远存在),毕竟,有可能明确表达任何给定lambda的(抽象)类型签名。

II. 二。 It is also possible to write a make_function wrapper (pretty much like std::make_pair and std::make_tuple ) to automatically convert a lambda f ( and other callables like function pointers/functors) to std::function , with the same type-deduction capabilities. 也可以编写一个make_function包装器(非常类似于std::make_pairstd::make_tuple ),以将lambda f (以及其他可调用对象,如函数指针/函子)自动转换为std::function ,具有相同的类型-演绎能力。

Test code is below: 测试代码如下:

#include <cstdlib>
#include <tuple>
#include <functional>
#include <iostream>
using namespace std;

// For generic types that are functors, delegate to its 'operator()'
template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
    //enum { arity = sizeof...(Args) };
    typedef function<ReturnType (Args...)> f_type;
};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) > {
    typedef function<ReturnType (Args...)> f_type;
};

// for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType (*)(Args...)>  {
  typedef function<ReturnType (Args...)> f_type;
};

template <typename L> 
typename function_traits<L>::f_type make_function(L l){
  return (typename function_traits<L>::f_type)(l);
}

long times10(int i) { return long(i*10); }

struct X {
  double operator () (float f, double d) { return d*f; } 
};

// test code
int main()
{
    auto lambda = [](int i) { return long(i*10); };
    typedef function_traits<decltype(lambda)> traits;
    traits::f_type ff = lambda;

    cout << make_function([](int i) { return long(i*10); })(2) << ", " << make_function(times10)(2) << ", " << ff(2) << endl;
    cout << make_function(X{})(2,3.0) << endl;

    return 0;
}

You are correct the types of C++11 lambdas are anonymous and instance-unique. 您是正确的C ++ 11 lambda类型是匿名的和实例唯一的。 the std::function type can store references to any kind of lambda I have come across, but there is said to be a performance hit. std::function类型可以存储对我遇到的任何类型的lambda的引用,但据说会影响性能。

Try 尝试

std::function<int (int, int)> f = [](int x, int y) -> int { 
    return x + y; 
};

note the -> int can be omitted in non ambiguous scenarios such as this. 注意,在这样的非歧义场景中,可以省略-> int

C++14 lets us write C ++ 14让我们编写

std::function<int (int, int)> f = [](auto x, auto y) { 
    return x + y; 
};

which is handy for long type names. 这对于长类型名称很方便。

As noted by @Jonathan Wakely, this approach captures a specific instantiation using std::function with fixed template arguments. 如@Jonathan Wakely所指出的,此方法使用带有固定模板参数的std :: function捕获特定的实例。 In C++14, template variables can be specified. 在C ++ 14中,可以指定模板变量。 Additionally, also per C++14, lambda parameters can have can have their types inferred via auto , allowing for the following: 此外,同样对于C ++ 14,可以通过auto推断lambda参数的类型,从而允许以下操作:

template<class T>
std::function<T (T, T)> g = [](auto x, auto y) -> auto {
    return x + y;
};

Currently, VC++, and GCC do not seem to support templates on variable declarations at function level, but allow them on member, namespace, and global declarations. 当前,VC ++和GCC似乎不支持在函数级别的变量声明上使用模板,但允许在成员,名称空间和全局声明上使用它们。 I am unsure whether or not this restriction emanates from the spec. 我不确定此限制是否源自规范。

Note: I do not use clang. 注意:我不使用clang。

在C ++ 1y中,存在通用的lambda,并且没有单个调用签名( operator()()是模板)。

I was wondering if there is a standard way to get the type signature (ie the return type and the types) of its parameters of any given lambda? 我想知道是否有一种标准方法来获取任何给定lambda参数的类型签名(即返回类型和类型)?

No, there isn't. 不,没有。

The reason I ask is that I've always wondered what exactly is the type auto in the declaration like auto l =[](int x,int y)->int{return x+y;} . 我想问的原因是,我一直想知道到底是什么类型auto像声明auto l =[](int x,int y)->int{return x+y;}

It's an unspecified class type, created by the implementation. 这是由实现创建的未指定的类类型。 The whole point of lambdas is they are "anonymous functions" ie you do not know their type. Lambda的全部要点是它们是“匿名函数”,即您不知道它们的类型。

If you want a known type then write a function object type. 如果要使用已知类型,请编写一个函数对象类型。

In other use cases of auto, it's a convenience and shorter alternative for a longer type name. 在auto的其他用例中,对于较长的类型名称,这是一种方便且较短的替代方法。 But for lambdas, is there even an alternative way to declare the lambda variable? 但是对于lambda,甚至还有另一种方法来声明lambda变量吗?

No. 没有。

If you want to declare the type yourself then don't use a lambda expression. 如果要自己声明类型,则不要使用lambda表达式。

My understanding is that a standard lambda is nothing more than a function object, and it is its own type. 我的理解是,标准的lambda仅仅是一个函数对象,而是它自己的类型。 So, even if two lambdas have the same return type and parameter types, they are still two different, unrelated classes/functors. 因此,即使两个lambda具有相同的返回类型和参数类型,它们仍然是两个不同的,不相关的类/函数。

Correct. 正确。 Each lamda expression generates a unique type. 每个lamda表达式都会生成一个唯一的类型。

But this there a way to capture the fact that they are the same in terms of type signature? 但这有没有办法捕捉到它们在类型签名方面相同的事实?

No, there is no language feature to allow that. 不,没有语言功能允许这样做。

I think the type signature I am looking for can be something like a std::function<> object of the correct types. 我认为我要寻找的类型签名可以是正确类型的std :: function <>对象。

Even if it was possible in C++11, it would not help in C++14 where lambda expressions can take any number and any type of argument, eg [](auto... a) { } 即使在C ++ 11中有可能,在C ++ 14中lambda表达式可以采用任何数字和任何类型的参数,例如[](auto... a) { } ,在C ++ 14中也无济于事

And anyway, if you don't know the call signature of your lambda function then I would say you are using lambdas wrong. 而且无论如何,如果您不知道lambda函数的调用签名,那么我会说您使用的lambda错误。 When you write the lambda you should know what its properties are, so either use it right away or put it in a std::function (or some other type that captures its call signature) as early as possible, when you know its properties. 编写lambda时,您应该知道其属性,因此,一旦知道其属性,则应立即使用它或将其放入std::function (或其他捕获其调用签名的其他类型)中。 If you're creating lambdas and using them non-locally where you don't know the call signature, you're doing it wrong. 如果您要创建lambda,并在不知道呼叫签名的地方非本地使用它们,那么您做错了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM