मैं नियमित रूप से C++ में लैम्ब्डा फ़ंक्शंस को परिभाषित करने के लिए boost.lambda (और फीनिक्स) का उपयोग करता हूं। मुझे वास्तव में उनकी बहुलक संपत्ति, उनके प्रतिनिधित्व की सादगी और जिस तरह से वे सी ++ में कार्यात्मक प्रोग्रामिंग करते हैं, उतना ही आसान है। कुछ मामलों में, यह छोटे कार्यों को परिभाषित करने और स्थिर दायरे में नाम देने के लिए उनका उपयोग करने के लिए भी क्लीनर और अधिक पठनीय (यदि आप उन्हें पढ़ने के लिए उपयोग किया जाता है) है।boost.lambda या boost.phoenix से स्टेटिक फ़ंक्शंस
इन functionals स्टोर करने के लिए जिस तरह से है कि पारंपरिक कार्यों जैसा दिखता है सबसे उन्हें एक boost::function
const boost::function<double(double,double)> add = _1+_2;
में कब्जा करने के लिए है लेकिन समस्या यह ऐसा करने का क्रम अक्षमता है। भले ही add
फ़ंक्शन स्टेटलेस है, लौटा हुआ लैम्ब्डा प्रकार खाली नहीं है और इसकी sizeof
1 से अधिक है (इसलिए boost::function
डिफ़ॉल्ट सीटीआर और कॉपी सीटीआर में new
शामिल होगा)। मैं वास्तव में संदेह संकलक या बढ़ावा की ओर से एक तंत्र इस statelessness का पता लगाने और कोड जो का उपयोग कर के बराबर है उत्पन्न करने के लिए यह है कि:
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
}
जीसीसी 4.6.1 इस कार्यक्रम से उत्पादन के साथ संकलित (अनुकूलन स्तर की परवाह किए बिना) है:
25
Segmentation fault
मैं अंत में लगभग मैं क्या करना चाहते हैं, तो निम्न दृष्टिकोण का उपयोग कर प्रबंधित किया है अपेक्षित के रूप में
। यहां, मैं लैम्ब्डा अभिव्यक्ति प्रकार (ऑप्टिमाइज़ेशन उद्देश्यों के लिए यथासंभव कॉन्स) के लिए स्थिर सूचकांक रख रहा हूं और इसे NULL
पर प्रारंभ कर रहा हूं। इस तरह, यदि आप राज्य के साथ लैम्ब्डा अभिव्यक्ति को "स्थिर" करने का प्रयास करते हैं, तो आप रनटाइम त्रुटि प्राप्त कर सकते हैं। और यदि आप वास्तव में एक स्टेटलेस लैम्ब्डा अभिव्यक्ति को स्थिर करते हैं, तो सब कुछ काम करता है।
प्रश्न (ओं) को पर:
विधि थोड़ा गंदा लगता है, आप किसी भी परिस्थिति, या संकलक धारणा है कि इस दुर्व्यवहार कर देगा के बारे में सोच सकते हैं (अपेक्षित व्यवहार: अच्छा काम करता है, तो लैम्ब्डा है स्टेटलेस, segfault अन्यथा)।
आप किसी भी तरह से सोच सकते हैं कि इस प्रयास कर जब लैम्ब्डा अभिव्यक्ति राज्य है एक संकलक त्रुटि के बजाय एक segfault का कारण होगा? एरिक 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
}
आईआईआरसी, यदि आप फीनिक्स का उपयोग कर रहे हैं, तो आप परिणाम को 'बूस्ट :: फ़ंक्शन' के बजाय 'बूस्ट :: फीनिक्स :: फ़ंक्शन' के अंदर स्टोर कर सकते हैं और कुछ दक्षता हानि को कम कर सकते हैं ('boost :: फीनिक्स: : फंक्शन 'पीओडी प्रकार हैं और संकलित समय पर स्थैतिक रूप से प्रारंभ किया जा सकता है)। – ildjarn
@ildjarn 'boost :: फीनिक्स :: फ़ंक्शन' के बारे में प्रमुखों के लिए धन्यवाद, जो कई मामलों में उपयोगी होने के लिए बाध्य है। मैं अभी भी देशी समकक्ष (रनटाइम-प्रदर्शन के अनुसार) लैम्ब्डा फ़ंक्शन कैप्चरिंग प्राप्त करने में रूचि रखता हूं। मुझे यकीन नहीं है कि यह उत्पादन गुणवत्ता बनाने के लिए संभव है, लेकिन मुझे पीछा दिलचस्प लगता है। – enobayram