2013-02-26 14 views
5

मैं std::thread documentation at cppreference (हमेशा 100% सटीक नहीं, मुझे पता है) के माध्यम से पढ़ रहा था और std::thread के व्यवहार के लिए निम्नलिखित परिभाषा को ध्यान में रखकर "पॉइंटर-टू-डेटा-सदस्य" (नहीं "सूचक करने वाली सदस्य समारोह") का पहला तर्क (f) और (थ्रेड-स्थानीय भंडारण करने के लिए कॉपी करने के बाद t1) ने अपने दूसरे तर्क के रूप में आवश्यक वर्ग की एक वस्तु के रूप:std :: थ्रेड के साथ डेटा सदस्य

एन हैं == 1 और f कक्षा के किसी सदस्य डेटा ऑब्जेक्ट के लिए सूचक है, तो इसे एक्सेस किया जाता है। वस्तु का मूल्य अनदेखा किया जाता है। प्रभावी रूप से, निम्नलिखित कोड निष्पादित किया गया है: t1। * F अगर और t1 का प्रकार या तो टी है, टी या (* t1) से व्युत्पन्न प्रकार के संदर्भ के संदर्भ में। * F अन्यथा।

अब, मैं इस तरह से std::thread का उपयोग करने की योजना नहीं बना रहा हूं, लेकिन मैं इस परिभाषा से flummoxed हूँ। जाहिर है, केवल एक चीज होती है कि डेटा सदस्य का उपयोग किया जाता है और मूल्य अनदेखा होता है, जो ऐसा प्रतीत नहीं होता है कि इसका कोई भी दुष्प्रभाव नहीं हो सकता है, जिसका अर्थ है (जहां तक ​​मैं कह सकता हूं) यह भी हो सकता है कोई को-अप। (मुझे कुछ स्पष्ट याद आ रही है ...?)

पहले, मैंने सोचा कि यह एक गलत छाप हो सकता है, और यह कहना है कि डेटा सदस्य का उपयोग किया जाता है और फिर कहा जाता है (क्योंकि यह एक कॉल करने योग्य वस्तु हो सकती है, यहां तक ​​कि अगर यह एक समारोह नहीं है), लेकिन मैं जीसीसी-4.7 में निम्न कोड के साथ यह परीक्षण किया है और वास्तव में वहाँ कोई कॉल नहीं है:

#include <iostream> 
#include <thread> 

struct S 
{ 
    void f() { 
     std::cout << "Calling f()" << std::endl; 
    } 

    struct { 
     void operator()() { 
      std::cout << "Calling g()" << std::endl; 
     } 
    } g; 
}; 

int main(int, char**) 
{ 
    S s; 
    s.f(); // prints "Calling f()" 
    s.g(); // prints "Calling g()" 

    std::cout << "----" << std::endl; 

    auto x = &S::f; // ptr-to-mem-func 
    auto y = &S::g; // ptr-to-data-mem 

    (s.*x)(); // prints "Calling f()" 
    (s.*y)(); // prints "Calling g()" 

    std::cout << "----" << std::endl; 

    std::thread t(x, &s); 
    t.join(); 
    // "Calling f()" printed by now 
    std::thread u(y, &s); 
    u.join(); 
    // "Calling g()" not printed 

    return 0; 
} 

वहाँ इस परिभाषा जो कुछ भी पूरा करने के लिए प्रतीत नहीं होता है करने के लिए किसी भी उद्देश्य है? इसके बजाय "पॉइंटर-टू-डेटा-सदस्य-कॉल करने योग्य" कार्य को "पॉइंटर-टू-सदस्य-फ़ंक्शन" की तरह क्यों नहीं गुजरते हैं, और एक "पॉइंटर-टू-डेटा-सदस्य-गैर-अक्षम" त्रुटि को गुजरते हैं? वास्तव में, ऐसा लगता है कि इसे लागू करने का सबसे आसान तरीका यह होगा कि, "पॉइंटर-टू-डेटा-सदस्य-कॉल करने योग्य" को कॉल करने के बाद अन्य संदर्भों में "पॉइंटर-टू-सदस्य-फ़ंक्शन" के रूप में कॉल करने के बराबर वाक्यविन्यास होता है (जब तक कि टेम्पलेट विशेषज्ञता और एसएफआईएनएई नियमों की कमजोरियों में कुछ न हो, जिससे उन्हें समान रूप से इलाज करना मुश्किल हो जाता है ...?)

यह वास्तविक कोड के लिए मुझे कुछ चाहिए, लेकिन तथ्य यह है कि यह परिभाषा मौजूद है, मुझे संदेह है कि मुझे संदेह है कि मुझे कुछ मौलिक याद आ रहा है, जो मुझे चिंतित करता है ... क्या कोई मुझे इस बारे में बता सकता है?

+0

+1 यह शब्द 'INVOKE' की परिभाषा से आता है, जो मानक के 20.8.2 में दिया गया है। 'INVOKE' परिभाषा में इस शब्द के बारे में विशेष रूप से आपके जैसा ही एक प्रश्न है: http://stackoverflow.com/questions/12638393/why-does-invoke-facility-in-the-c11- मानक-refer डेटा-सदस्य – jogojapan

उत्तर

3

यह सामान्य बाध्यकारी सुविधा के कारण है जिसके संदर्भ में सी ++ 11 मानक न केवल धागा शुरू होता है, बल्कि std::bind और std::function कार्य को परिभाषित करता है।

वास्तव में, अनुच्छेद की 30.3.1.2/3 सी ++ 11 स्टैंडर्ड वर्ग std::thread की variadic निर्माता के बारे में निर्दिष्ट करता है:

template <class F, class ...Args> explicit thread(F&& f, Args&&... args);

प्रभाव: प्रकार धागे की एक वस्तु निर्माणों । निष्पादन का नया धागा INVOKE (DECAY_- COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) को DECAY_COPY पर कॉलिंग थ्रेड में मूल्यांकन के साथ निष्पादित करता है। इस आमंत्रण से कोई भी वापसी मूल्य अनदेखा किया गया है। [...]

DECAY_COPY क्या यह अनदेखा करता है (यह प्रश्न के लिए प्रासंगिक नहीं है), यह पैराग्राफ 20.8 है।2 को परिभाषित करता है INVOKE छद्म समारोह:

आह्वान (च, T1, T2, ..., TN) को परिभाषित करें प्रकार है: - (। T1 * च)

(टी 2, .. ।, टीएन) जब एफ कक्षा टी और टी 1 के सदस्य फ़ंक्शन के लिए सूचक होता है तो प्रकार टी या किसी प्रकार की वस्तु के संदर्भ में टी या टी से व्युत्पन्न प्रकार के किसी ऑब्जेक्ट का संदर्भ होता है;

- ((* टी 1)। * एफ) (टी 2, ..., टीएन) जब एफ कक्षा टी और टी 1 के सदस्य फ़ंक्शन के लिए सूचक है, तो पिछले आइटम में वर्णित प्रकारों में से में से एक नहीं है ;

-। T1 * च जब एन == 1 और च एक वर्ग टी और t1 के सदस्य डेटा के लिए सूचक है प्रकार टी की एक वस्तु या प्रकार टी का एक उद्देश्य के लिए एक संदर्भ या किसी वस्तु के लिए एक संदर्भ है टी से व्युत्पन्न एक प्रकार का;

- (* टी 1)। * एफ जब एन == 1 और एफ कक्षा टी और टी 1 के सदस्य डेटा के लिए सूचक है, तो पिछले आइटम में वर्णित प्रकारों में से एक नहीं है;

- एफ (टी 1, टी 2, ..., टीएन) अन्य सभी मामलों में।

अब प्रश्न बन जाता है:

सी ++ 11 स्टैंडर्ड क्यों परिभाषित करता है INVOKE सुविधा कि जिस तरह से?

और जवाब here है।

+1

धन्यवाद, मैं समझता हूं कि व्यवहार अब से कहां से आ रहा है लेकिन मैं अभी भी इसका पालन नहीं करता क्यों ... आप वास्तव में सदस्य डेटा को बाध्यकारी क्यों परिभाषित करेंगे? बस इतना है कि आप std :: mem_fn का उपयोग कर डेटा सदस्य पुनर्प्राप्त कर सकते हैं? अगर मैं f = std :: mem_fn (& X :: n) को बाध्य करता हूं और फिर f (& x) कहा जाता है, तो मुझे या तो त्रुटि या xn(), xn नहीं चाहिए .. सदस्य डेटा को बाध्य करने के लिए वैध उपयोग केस हो सकता है इस तरह, लेकिन क्यों std :: mem_data नामक किसी चीज़ के माध्यम से नहीं? –

+0

@ स्टीफनलिन: जबकि मैं आपकी बात समझता हूं, मेरा मानना ​​है कि इस तरह के प्रश्नों के लिए एसओ एक अच्छा फिट नहीं है "* अन्यथा की बजाय चीजें क्यों हैं? *"। मैंने उस हिस्से का जवाब देने की कोशिश की जिसे निष्पक्ष उत्तर दिया जा सके। उम्मीद है कि बेहतर जवाब दिए जाएंगे। –

+0

कोई समस्या नहीं, पूछने का मेरा एकमात्र कारण यह है कि आपने उस उत्तर से एक स्पष्टीकरण के रूप में लिंक किया है, जो कुछ भी समझा नहीं जाता है (इसके अलावा किसी को यह अधिभारित व्यवहार उपयोगी हो सकता है ...) –

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