私は定期的にboost.lambda(とphoenix)を使ってC++でラムダ関数を定義しています。多態性、その表現の簡潔さ、そしてC++での関数型プログラミングのやり方がずっと簡単なのは本当に好きです。場合によっては、小さな関数を定義したり、静的なスコープで名前を付けるためにそれらを使用するためには、よりクリーンで読みやすい(読み込みに慣れている)人もいます。ほとんどの従来の機能に似ているこれらの汎関数を格納するためのboost.lambdaやboost.phoenixの静的関数
方法はboost::function
const boost::function<double(double,double)> add = _1+_2;
でそれらをキャプチャすることですしかし、問題はそうすることの実行時の非効率性です。ここでadd
の機能がステートレスであっても、返されるラムダ型は空ではなく、sizeof
は1よりも大きいため(boost::function
デフォルトのctorとcopy ctorにはnew
が含まれます)。
auto
Cを使用することができます
double (* const add)(double,double) = _1+_2; //not valid right now
が、その後、変数:私は本当にこのステートレスを検出して使用することと等価であるコードを生成するコンパイラのかブースト者側からのメカニズムがあることを疑いますテンプレート化されていないコンテキストの周りを渡すことはできません。 GCC 4.6.1このプログラムからの出力でコンパイル
が#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
}
(関係なく、最適化レベルの)です:
25
Segmentation fault
私は最終的に次のようなアプローチを使用して、ほとんど私がやりたいことができました
が期待通りです。ここでは、ラムダ式型(最適化のために可能な限りconstとして)への静的ポインタを保持し、それをNULL
に初期化しています。このように、ラムダ式をstateで "静的化"しようとすると、実行時エラーが発生します。真に無国籍のラムダ式を静的にすると、すべてがうまくいきます。質問(複数可)をオン
:メソッドは、この不正な動作を行いますどんな状況、またはコンパイラの前提と考えることができ、少し汚れているようだ
は(期待される動作は:ラムダの場合は正常に動作しますステートレス、segfault)。
ラムダ式に状態があるときにsegfaultの代わりにコンパイラエラーが発生すると思いますか?エリックNieblerの答えの後
EDIT:
#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
}
Phoenixを使用している場合、結果を 'boost :: function'ではなく' boost :: phoenix :: function'の中に格納して、効率を低下させることができます( 'boost :: phoenix: :function'はPOD型であり、コンパイル時に静的に初期化することができます)。 – ildjarn
@ildjarn 'boost :: phoenix :: function'について頭をおいてくれてありがとうございました。これは多くの場合に役立つはずです。私はまだキャプチャネイティブ同等の(ランタイムパフォーマンス賢明な)ラムダ関数を得ることに興味があります。私はこの生産品質を作ることがすべて可能かどうかはわかりませんが、興味深いのがわかります。 – enobayram