我经常使用boost.lambda(和凤凰)在C中定义lambda函数++。 我真的很喜欢他们的多态性的财产,他们代表的简单性和他们的方式使函数式编程的C ++容易得多。 在某些情况下,它甚至更清洁,更可读的(如果你已经习惯了阅读他们)用它们来定义小功能,在静态范围命名它们。
存储这些函类似于常规功能最的方法是捕捉它们在boost::function
const boost::function<double(double,double)> add = _1+_2;
但问题是,这样做的效率运行。 即使add
在这里的功能是无状态的,返回的拉姆达类型不是空的,它sizeof
大于1(因此boost::function
的默认构造函数和拷贝构造函数将涉及new
)。 我真的很怀疑,有一个从编译器或升压转换器的一侧,以检测这种无国籍和生成代码等同于使用一种机制:
double (* const add)(double,double) = _1+_2; //not valid right now
当然,人们可以使用C ++ 11 auto
,但随后的变量不能左右的非模板上下文进行传递。 我终于成功地做到几乎我想要的东西,使用以下方法:
#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;
#include <boost/type_traits.hpp>
#include <boost/utility/result_of.hpp>
using namespace boost;
template <class T>
struct static_lambda {
static const T* const t;
// Define a static function that calls the functional t
template <class arg1type, class arg2type>
static typename result_of<T(arg1type,arg2type)>::type
apply(arg1type arg1,arg2type arg2){
return (*t)(arg1,arg2);
}
// The conversion operator
template<class func_type>
operator func_type*() {
typedef typename function_traits<func_type>::arg1_type arg1type;
typedef typename function_traits<func_type>::arg2_type arg2type;
return &static_lambda<T>::apply<arg1type,arg2type>;
}
};
template <class T>
const T* const static_lambda<T>::t = 0;
template <class T>
static_lambda<T> make_static(T t) {return static_lambda<T>();}
#include <iostream>
#include <cstdio>
int main() {
int c=5;
int (*add) (int,int) = make_static(_1+_2);
// We can even define arrays with the following syntax
double (*const func_array[])(double,double) = {make_static(_1+_2),make_static(_1*_2*ref(c))};
std::cout<<func_array[0](10,15)<<"\n";
std::fflush(stdout);
std::cout<<func_array[1](10,15); // should cause segmentation fault since func_array[1] has state
}
用gcc 4.6.1编译该程序的输出是(不管优化级别的):
25
Segmentation fault
如预期。 在这里,我保持一个静态指针lambda表达式类型(常量尽可能优化的目的),并对其进行初始化,以NULL
。 这样,如果你尝试“staticify”与状态的lambda表达式,你一定会得到一个运行时错误。 如果你staticify一个真正的无状态的lambda表达式,一切顺利。
到问题(S):
该方法似乎有点脏,你能想到的任何情况下,或编译器的假设,这将使这个行为不端的(预期的行为:正常工作,如果拉姆达是无状态的,否则段错误)。
你能想到的任何方式企图,这将导致一个编译器错误,而不是段错误时,lambda表达式有状态?
埃里克Niebler的回答后编辑:
#include <boost/phoenix.hpp>
using namespace boost::phoenix;
using namespace boost::phoenix::arg_names;
#include <boost/type_traits.hpp>
#include <boost/utility/result_of.hpp>
using boost::function_traits;
template <class T>
struct static_lambda {
static const T t;
// A static function that simply applies t
template <class arg1type, class arg2type>
static typename boost::result_of<T(arg1type,arg2type)>::type
apply(arg1type arg1,arg2type arg2){
return t(arg1,arg2);
}
// Conversion to a function pointer
template<class func_type>
operator func_type*() {
typedef typename function_traits<func_type>::arg1_type arg1type;
typedef typename function_traits<func_type>::arg2_type arg2type;
return &static_lambda<T>::apply<arg1type,arg2type>;
}
};
template <class T>
const T static_lambda<T>::t; // Default initialize the functional
template <class T>
static_lambda<T> make_static(T t) {return static_lambda<T>();}
#include <iostream>
#include <cstdio>
int main() {
int (*add) (int,int) = make_static(_1+_2);
std::cout<<add(10,15)<<"\n";
int c=5;
// int (*add_with_ref) (int,int) = make_static(_1+_2+ref(c)); causes compiler error as desired
}