c++11/1y lambda 函数的类型签名是什么?
我想知道是否有一种标准方法可以获取任何给定 lambda 的参数的类型签名(即返回类型和类型)?
I was wondering if there is a standard way to get the type signature (i.e. the return type and the types) of its parameters of any given lambda?
我问的原因是我一直想知道像 auto l =[](int x,int y)->int 这样的声明中
.在 auto
的类型到底是什么{返回 x+y;}auto
的其他用例中,对于较长的类型名称,它是一种方便且较短的替代方案.但是对于 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;}
. In other use cases of auto
, it's a convenience and shorter alternative for a longer type name. 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. So, even if two lambdas have the same return type and parameter types, they are still two different, unrelated classes/functors. But this there a way to capture the fact that they are the same in terms of type signature?
我认为我正在寻找的类型签名可以是正确类型的 std::function<>
对象.
I think the type signature I am looking for can be something like a std::function<>
object of the correct types.
一个更有用/涉及的问题是,如果可以提取类型签名,则可以编写一个通用包装函数来将任何 lambda 函数转换为相同类型的签名.
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表达式的'类型'吗?,在目前的c++中(不需要c++1y)其实有一个简单的方法来计算return_type和参数lambda 的类型.适应这一点,为每个 lambda 组装一个 std::function
类型签名类型(下面称为 f_type
)并不困难.
According to Can the 'type' of a lambda expression be expressed?, 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. Adapting this, it is not difficult to assemble a std::function
typed signature type (called f_type
below) for each lambda.
我.有了这个抽象类型,实际上可以有一种替代 auto
的方式来表达 lambda 的类型签名,即下面的 function_traits<..>::f_type
.注意:f_type
不是 lambda 的真正类型,而是 lambda 在功能方面的类型签名的摘要.然而,它可能比 lambda 的实际类型更有用,因为每个 lambda 都是它自己的类型.
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. 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. It is however, probably more useful than the real type of a lambda because every single lambda is its own type.
如下代码所示,就像可以使用vector
,也可以使用function_traits
,这是神秘的auto
的替代.当然,这种相似性只是形式上的.下面的代码涉及将 lambda 转换为 std::function
,其代价是构建 std::function
对象的类型擦除成本和通过间接调用的小成本std::function
对象.但是除了这些使用 std::function
的实现问题(我认为这不是基本的,应该永远存在),毕竟,有可能明确表达的(抽象)类型签名任何给定的 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
. 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. 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.
二.也可以编写一个 make_function
包装器(很像 std::make_pair
和 std::make_tuple
)来自动转换一个 lambda f
(以及其他可调用对象,如函数指针/函子)到 std::function
,具有相同的类型推导能力.
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.
测试代码如下:
#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;
}
相关文章