2014-10-09 15 views
5

के साथ संलयन संलयन फोल्ड को बढ़ावा देने के लिए मैं एक सामान्य लैम्ब्डा फ़ंक्शन को बढ़ावा देने की कोशिश कर रहा हूं :: फ़्यूज़न :: फोल्ड फ़ंक्शन ताकि मैं बूस्ट :: फ़्यूज़न :: के सभी तत्वों को पुन: सक्रिय कर सकूं। वेक्टर। मेरा लक्ष्य वेक्टर में प्रत्येक तत्व से गैर-कॉन्स सदस्य फ़ंक्शन को कॉल करना है। समस्या यह है कि भले ही वेक्टर गैर-कॉन्स मान रखता है, जेनेरिक लैम्ब्डा द्वारा प्रदत्त प्रकार एक कॉन्स संदर्भ है। इसके परिणामस्वरूप मेरे जीसीसी -4.9.0 कंपाइलर (साइगविन का उपयोग करके) शिकायत करते हैं कि मैं कॉन्स्ट क्वालीफायर को छोड़ रहा हूं।सी ++: सी ++ 14 जेनेरिक लैम्ब्स

#include <iostream>           
#include <boost/fusion/include/vector.hpp>        
#include <boost/fusion/include/fold.hpp>        
#include <boost/fusion/include/for_each.hpp>        

class Silly {            

public:             
    Silly(int x)            
    : x_(x){}            

    int increment(int i) {          
    return x_ += i;           
    }                                   

private:            
    int x_;            
};             

using my_type = boost::fusion::vector<Silly, Silly>;       


int main() {            
    my_type my_vector(1, 2);          
    boost::fusion::fold(my_vector, 0, [](int i, auto& x){return x.increment(i);}); //error: passing 'const Silly' as 'this' argument of 'int Silly::increment(int)' discards qualifiers          
}                        

अब, अगर लैम्ब्डा के बजाय मैं निम्नलिखित functor गुजरती हैं, कार्यक्रम सफाई से संकलित

struct functor { 

    template <class X> 
    int operator()(int i, X& x) { 
    return x.increment(i); 
} 
}; 

इस एक बढ़ावा :: संलयन बग है या मैं कुछ याद आ रही है? अग्रिम में धन्यवाद!

+0

@ टी.सी. ओह, धन्यवाद। – dyp

+2

इसे रिटर्न प्रकार कटौती के साथ करना है। यह तत्काल संदर्भ में एक प्रतिस्थापन विफलता पैदा नहीं करता है। सबूत: स्पष्ट रूप से लैम्ब्डा के रिटर्न प्रकार को निर्दिष्ट करें, और यह ठीक काम करता है। – dyp

+0

@ dyp ~: धन्यवाद, यह काम करता है। यदि आप इसे उत्तर देते हैं तो मैं इसे स्वीकार करूंगा :) क्या आप यह भी बता सकते हैं कि यह वास्तव में कहां विफल रहता है? धन्यवाद फिर से – linuxfever

उत्तर

4

कई boost::fusion::fold ओवरलोड हैं। boost's svn repo से:

template<typename Seq, typename State, typename F> 
inline typename result_of::BOOST_FUSION_FOLD_NAME< 
    Seq const 
    , State const 
    , F 
>::type 
BOOST_FUSION_FOLD_NAME(Seq const& seq, State const& state, F f) 
{ 
    return result_of::BOOST_FUSION_FOLD_NAME<Seq const,State const,F>::call(
     state, 
     seq, 
     f); 
} 

template<typename Seq, typename State, typename F> 
inline typename result_of::BOOST_FUSION_FOLD_NAME< 
    Seq 
    , State const 
    , F 
>::type 
BOOST_FUSION_FOLD_NAME(Seq& seq, State& state, F f) 
{ 
    return result_of::BOOST_FUSION_FOLD_NAME<Seq,State,F>::call(
     state, 
     seq, 
     f); 
} 

template<typename Seq, typename State, typename F> 
inline typename result_of::BOOST_FUSION_FOLD_NAME< 
    Seq const 
    , State const 
    , F 
>::type 
BOOST_FUSION_FOLD_NAME(Seq const& seq, State& state, F f) 
{ 
    return result_of::BOOST_FUSION_FOLD_NAME<Seq const,State,F>::call(
     state, 
     seq, 
     f); 
} 

संकलक एक बार प्रकार कटौती और प्रतिस्थापन सफल रहा है इन सभी वेरिएंट के लिए वर्ग टेम्पलेट result_of::BOOST_FUSION_FOLD_NAME(*) वापसी प्रकार में दृष्टांत के लिए, से पहले एक अधिभार चयन किया जाता है की अनुमति है। इस मामले में, यह निर्धारित करने के लिए कि रिटर्न प्रकार मान्य है या नहीं, संकलक को इस क्लास टेम्पलेट को तुरंत चालू करना होगा। यदि रिटर्न प्रकार में प्रतिस्थापन (टेम्पलेट तर्कों का) एक अमान्य प्रकार तत्काल संदर्भ में जाता है, तो ओवरलोड को त्याग दिया जाता है। इसे SFINAE के रूप में जाना जाता है।

(*) यह नाम आम तौर पर result_of::fold पर हल करता है।

Seq const& पैरामीटर वाले ओवरलोड में से एक का तत्कालता लैम्बडा के रिटर्न प्रकार को निर्धारित करने के लिए अब कोशिश करता है। हालांकि, के साथ लैम्ब्डा को तुरंत चालू करना दूसरा तर्क विफल रहता है: increment किसी कॉन्स्ट ऑब्जेक्ट पर नहीं कहा जा सकता है (यह संकलक आपको बताता है)।

यदि रिटर्न प्रकार का निर्धारण विफल रहता है, तो fold ओवरलोड में प्रतिस्थापन विफलता होनी चाहिए, हम वापसी प्रकार निर्धारित करने का प्रयास कर रहे हैं। हालांकि, लैम्बडास में स्वचालित रिटर्न प्रकार कटौती के कारण प्रतिस्थापन विफलता और सी ++ 14 फ़ंक्शंस मूल टेम्पलेट fold के तत्काल संदर्भ में नहीं हैं: के भीतर होता है जो स्वचालित रिटर्न प्रकार कटौती (यहां: लैम्ब्डा) का उपयोग करने वाले फ़ंक्शन का होता है।

मूल प्रतिस्थापन के तत्काल संदर्भ में एक प्रतिस्थापन विफलता नहीं है एक कठिन त्रुटि है, यह एक SFINAE-प्रकार त्रुटि नहीं है जिसे आप पुनर्प्राप्त कर सकते हैं। (SFINAE = SFIICINAE)

यदि आप स्पष्ट रूप से लैम्ब्डा, [](int i, auto& x) -> int {return x.increment(i);} के रिटर्न प्रकार को निर्दिष्ट करते हैं, तो फ़ंक्शन/लैम्ब्डा को रिटर्न प्रकार निर्धारित करने के लिए तत्काल आवश्यकता नहीं है। इसे अकेले घोषणा से निर्धारित किया जा सकता है। इसलिए, किसी भी ओवरलोड के लिए रिटर्न प्रकार के आधार पर कोई प्रतिस्थापन विफलता नहीं होती है, और सामान्य ओवरलोड रिज़ॉल्यूशन उचित अधिभार का चयन कर सकता है। गैर-कॉन्स Seq& अधिभार चुना जाता है, और लैम्ब्डा का त्वरण मान्य होगा।

इसी प्रकार, स्पष्ट रूप से लिखित मज़ेदार के लिए: यदि रिटर्न प्रकार को फ़ंक्शन को तत्काल किए बिना निर्धारित किया जा सकता है, तो कोई त्रुटि नहीं होगी।आप साधारण कार्यों के लिए सी ++ 14 की वापसी प्रकार कटौती का उपयोग करते हैं, एक ही समस्या होती है:

struct functor { 
    template <class X> 
    auto operator()(int i, X& x) { 
    return x.increment(i); 
} 
}; 

एक पक्ष टिप्पणी के रूप में: T.C. एक comment में बताया गया है, एक कठिन त्रुटि भी निम्न कार्य के लिए होता है ऑब्जेक्ट प्रकार: फिर, सभी fold भार के अपने-अपने प्रकार के साथ result_of::fold वर्ग टेम्पलेट का दृष्टांत की जरूरत है:

struct functor { 
    int operator()(int i, Silly& x) { 
    return x.increment(i); 
} 
}; 

कारण यह विफल रहता है अलग है, हालांकि है। यह वर्ग टेम्पलेट तत्काल संदर्भ में प्रतिस्थापन त्रुटियों का उत्पादन नहीं करता है: यदि पारित कार्य को पारित तर्क प्रकारों के साथ नहीं कहा जा सकता है, तो एक कठिन त्रुटि उत्पन्न होगी।

int(int, Silly&) प्रकार के फ़ंक्शन के प्रकार int और के तर्कों के साथ नहीं कहा जा सकता है, तो एक कठिन त्रुटि होती है।

जब एक टेम्पलेट के रूप में ऑपरेटर का प्रयोग (सी ++ 14 वापसी प्रकार कटौती के साथ उदाहरण के रूप में) लेखन, operator() टेम्पलेट के घोषणा प्रकार का एक दूसरा तर्क के लिए instantiated जा सकता है (X निष्कर्ष निकाला की जाएगी Silly const होने के लिए)। फ़ंक्शन परिभाषा को तत्काल नहीं किया जा सकता है, हालांकि, इसके परिणामस्वरूप OP: Silly::increment में एक ही त्रुटि होगी जिसके परिणामस्वरूप गैर-कॉन्स Silly ऑब्जेक्ट की आवश्यकता होती है।

फ़ंक्शन की परिभाषा का तत्कालता केवल ओवरलोड रिज़ॉल्यूशन के बाद होती है यदि कोई वापसी प्रकार कटौती नहीं है। इसलिए, यह प्रतिस्थापन विफलताओं का उत्पादन नहीं करेगा।

+0

अनुमोदित, यह एक अस्पष्ट समस्या है। यदि boost.fusion मूल रूप से> = C++ 11 के लिए लिखा गया था, तो हमें यह समस्या नहीं हो सकती है, क्योंकि संभवतया एक 'फ़ोल्ड' टेम्पलेट फॉरवर्डिंग संदर्भ लेना होगा। – dyp

+1

+1। यह काम करता है अगर रिटर्न प्रकार स्पष्ट रूप से प्रदान किया जाता है क्योंकि फिर वापसी प्रकार अकेले घोषणा से निर्धारित किया जा सकता है और इसलिए संकलक को टेम्पलेट 'ऑपरेटर()' की परिभाषा को तत्काल प्रारंभ करने की अनुमति नहीं है। इसके विपरीत, प्रश्न में 'स्ट्रक्चर मज़ेदार' तोड़ देगा यदि उसके 'ऑपरेटर() 'के रिटर्न प्रकार को' ऑटो 'बनाया जाता है। –

+0

@ टी.सी. आह, हाँ, मैंने ओपी को टिप्पणी में उल्लेख किया है, लेकिन इसे यहां जोड़ना भूल गया। इसे जोड़ा गया – dyp

संबंधित मुद्दे