2015-06-21 11 views
5

निम्नलिखित कोड संकलन नहीं करता है:std :: बाँध और सही अग्रेषण

#include <functional> 

template<class ...Args> 
void invoke(Args&&... args) 
{ 
} 

template<class ...Args> 
void bind_and_forward(Args&&... args) 
{ 
    auto binder = std::bind(&invoke<Args...>, std::forward<Args>(args)...); 
    binder(); 
} 

int main() 
{ 
    int a = 1; 
    bind_and_forward(a, 2); 
} 

अगर मैं सही ढंग से समझ, कारण इस प्रकार है: std::bind प्रतियां अपने तर्कों, और जब binder के operator() कहा जाता है, यह lvalues ​​ के रूप में सभी बाध्य तर्कों को पास करता है - यहां तक ​​कि bindरैवल्यू के रूप में दर्ज किए गए भी हैं। लेकिन invoke को मूल तर्कों के लिए तत्काल किया गया था, और यह स्वीकार नहीं कर सकता कि binder इसे पारित करने का प्रयास करता है।

क्या इस समस्या के लिए कोई समाधान है?

उत्तर

4

आपकी समझ सही है - bind इसके तर्कों की प्रतिलिपि बनाता है।

template<class ...Args> 
void bind_and_forward(Args&&... args) 
{ 
    auto binder = std::bind(&invoke<Args&...>, std::forward<Args>(args)...); 
            ^^^^^^^^ 
    binder(); 
} 

यह सबसे प्रकार पर काम करता है: तो आप invoke() का सही अधिभार कि lvalues ​​पर कहा जा सकता है प्रदान करने के लिए है। operator() के लिए [func.bind.bind] में उल्लिखित कुछ अपवाद हैं, जहां Arg& अपर्याप्त है। जैसा कि आप इंगित करते हैं, std::reference_wrapper<T> है। हम एक प्रकार के गुण के साथ उपरोक्त Args& उपयोग को प्रतिस्थापित करके उस पर जा सकते हैं। आमतौर पर, हम सिर्फ एक lvalue संदर्भ जोड़ने चाहते हैं, लेकिन reference_wrapper<T> लिए, हम बस T& हैं:

template <typename Arg> 
struct invoke_type 
: std::add_lvalue_reference<Arg> { }; 

template <typename T> 
struct invoke_type<std::reference_wrapper<T>> { 
    using type = T&; 
}; 

template <typename T> 
using invoke_type_t = typename invoke_type<T>::type; 

प्लग कि मूल समाधान में वापस, और हम कुछ है कि reference_wrapper के लिए भी काम करता है मिलती है:

template<class ...Args> 
void bind_and_forward(Args&&... args) 
{ 
    auto binder = std::bind(&invoke<invoke_type_t<Args>...>, 
          //  ^^^^^^^^^^^^^^^^^^^ 
          std::forward<Args>(args)...); 
    binder(); 
} 

बेशक, यदि Arg में से कोई एक प्लेसहोल्डर है तो यह वैसे भी काम नहीं करेगा। और यदि यह एक बाध्य अभिव्यक्ति है, तो आपको कुछ और लिखना होगा।

+0

लेकिन ऐसे मामले में यह 'std :: ref()' के साथ लिपटे तर्क के लिए संकलित नहीं होगा। –

+0

@ इगोरआर। उस के लिए अपडेट किया गया - 'बाइंड()' 'std :: ref()' के लिए कुछ खास करता है। तो आपको कुछ खास करना होगा। – Barry

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