我想知道是否有一种标准方法来获取任何给定lambda的参数的类型签名(即返回类型和类型)?
我问的原因是我一直想知道auto
声明中的类型究竟是什么样的auto l =[](int x,int y)->int{return x+y;}
.在其他用例中auto
,对于较长的类型名称而言,它是一种便利和更短的替代方案.但是对于lambdas,是否有另一种方法来声明lambda变量?
我的理解是标准lambda只不过是一个函数对象,它是它自己的类型.因此,即使两个lambda具有相同的返回类型和参数类型,它们仍然是两个不同的,不相关的类/仿函数.但是有一种方法可以捕捉它们在类型签名方面相同的事实吗?
我认为我正在寻找的类型签名可能类似于std::function<>
正确类型的对象.
更有用/涉及的问题是,如果可以提取类型签名,则可以编写一般包装函数将任何lambda函数转换std::function
为相同类型签名的对象.
tin*_*lyx 17
根据可以表达lambda表达式的"类型"吗?,实际上有一种简单的方法在当前的c ++中(不需要c ++ 1y)来计算lambda的return_type和参数类型.为了适应这一点,为每个lambda 组装一个std::function
类型化的签名类型(f_type
下面称为)并不困难.
I.对于这种抽象类型,实际上可以有一种替代方式来auto
表达lambda的类型签名,即function_traits<..>::f_type
下面.注意:f_type
它不是lambda的真实类型,而是函数术语中lambda类型签名的摘要.然而,它可能比lambda的真实类型更有用,因为每个lambda都是它自己的类型.
如下面的代码所示,就像人们可以使用一样vector<int>::iterator_type i = v.begin()
,也可以做function_traits<lambda>::f_type f = lambda
,这是神秘的替代品auto
.当然,这种相似性只是正式的.下面的代码涉及将lambda转换为a std::function
,在构造std::function
对象时具有类型擦除的成本,并且通过std::function
对象进行间接调用的成本很小.但是这些使用std::function
旁边的实现问题(我不认为这是基本的并且应该永远存在),毕竟,有可能明确地表达任何给定lambda的(抽象)类型签名.
II.也可以使用相同的类型推导功能编写一个make_function
包装器(非常类似于std::make_pair
和std::make_tuple
)来自动将lambda f
(以及其他类似指针/函数的callables )转换为std::function
.
测试代码如下:
#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;
}
Run Code Online (Sandbox Code Playgroud)
Alu*_*dad 12
你是对的,C++ 11 lambdas的类型是匿名的,而且是实例唯一的.该std::function
类型可以存储我遇到的任何类型的lambda的引用,但据说是性能损失.
尝试
std::function<int (int, int)> f = [](int x, int y) -> int {
return x + y;
};
Run Code Online (Sandbox Code Playgroud)
请注意,-> int
在此类非模糊场景中可以省略.
C++ 14让我们写
std::function<int (int, int)> f = [](auto x, auto y) {
return x + y;
};
Run Code Online (Sandbox Code Playgroud)
这对于长型名称来说很方便.
正如@Jonathan Wakely所指出的,这种方法使用带有固定模板参数的std :: function捕获特定的实例化.在C++ 14中,可以指定模板变量.另外,根据C++ 14,lambda参数可以通过它们推断出它们的类型auto
,允许以下内容:
template<class T>
std::function<T (T, T)> g = [](auto x, auto y) -> auto {
return x + y;
};
Run Code Online (Sandbox Code Playgroud)
目前,VC++和GCC似乎不支持函数级别的变量声明模板,但允许在成员,命名空间和全局声明上使用它们.我不确定这种限制是否来自规范.
注意:我不使用clang.