2011-12-01 19 views
18

क्यों निम्नलिखित कोड मान्य है:एक सही अग्रेषण समारोह क्यों टेम्पलेट किया जाना चाहिए?

template<typename T1> 
void foo(T1 &&arg) { bar(std::forward<T1>(arg)); } 

std::string str = "Hello World"; 
foo(str); // Valid even though str is an lvalue 
foo(std::string("Hello World")); // Valid because literal is rvalue 

लेकिन नहीं:

void foo(std::string &&arg) { bar(std::forward<std::string>(arg)); } 

std::string str = "Hello World"; 
foo(str); // Invalid, str is not convertible to an rvalue 
foo(std::string("Hello World")); // Valid 

क्यों उदाहरण 2 में lvalue एक ही तरीके है कि यह उदाहरण 1 में करता है में हल नहीं करता है?

इसके अलावा, मानक को यह समझने में महत्वपूर्ण क्यों लगता है कि तर्क प्रकार को आगे बढ़ाना आसान बनाम std :: आगे बना रहा है? बस कॉल करने के बावजूद, आगे कॉल करना इरादा दिखा रहा है।

यदि यह मानक चीज़ नहीं है और केवल मेरा कंपाइलर है, तो मैं msvc10 का उपयोग कर रहा हूं, जो क्रैपी सी ++ 11 समर्थन की व्याख्या करेगा।

धन्यवाद

संपादित करें 1: बदल दिया शाब्दिक "नमस्ते दुनिया" एसटीडी जा करने के लिए :: स्ट्रिंग ("हैलो दुनिया") एक rvalue बनाने के लिए।

+0

बार में क्या होता है? संकलन का मतलब यह नहीं है कि यह जरूरी काम कर रहा है। मेरा मानना ​​है कि यह क्रमशः 'शून्य फू (टी 1 और तर्क) 'और' शून्य फू (std :: स्ट्रिंग और तर्क) होना चाहिए। – AJG85

+1

'" हैलो वर्ल्ड "' एक रैल्यू नहीं है, यह 'const char [12]' प्रकार के साथ एक अंतराल है। – GManNickG

+0

@ AJG85 बार में क्या होता है महत्वपूर्ण नहीं है। && का मतलब है rvalue संदर्भ। – Mranz

उत्तर

15

सबसे पहले, read this अग्रेषण का पूरा विचार प्राप्त करने के लिए। (हां, मैं इस उत्तर का अधिकतर जवाब कहीं और दे रहा हूं।)

सारांशित करने के लिए, अग्रेषण का अर्थ है कि अंतराल अंतराल और राजस्व बने रहते हैं। आप इसे एक ही प्रकार से नहीं कर सकते हैं, इसलिए आपको दो की आवश्यकता है। तो प्रत्येक अग्रेषित तर्क के लिए, आपको उस तर्क के लिए दो संस्करणों की आवश्यकता है, जिसके लिए फ़ंक्शन के लिए 2 एन संयोजन की आवश्यकता होती है। आप फ़ंक्शन के सभी संयोजनों को कोड कर सकते हैं, लेकिन यदि आप टेम्पलेट का उपयोग करते हैं तो आवश्यकतानुसार आपके लिए विभिन्न संयोजन उत्पन्न होते हैं।


आप इस तरह के रूप में प्रतियां और चालें, अनुकूलन करने के लिए प्रयास कर रहे हैं:

struct foo 
{ 
    foo(const T& pX, const U& pY, const V& pZ) : 
    x(pX), 
    y(pY), 
    z(pZ) 
    {} 

    foo(T&& pX, const U& pY, const V& pZ) : 
    x(std::move(pX)), 
    y(pY), 
    z(pZ) 
    {} 

    // etc.? :(

    T x; 
    U y; 
    V z; 
}; 

तो फिर तुम बंद करो और यह इस तरह से करना चाहिए:

struct foo 
{ 
    // these are either copy-constructed or move-constructed, 
    // but after that they're all yours to move to wherever 
    // (that is, either: copy->move, or move->move) 
    foo(T pX, U pY, V pZ) : 
    x(std::move(pX)), 
    y(std::move(pY)), 
    z(std::move(pZ)) 
    {} 

    T x; 
    U y; 
    V z; 
}; 

आप केवल एक की जरूरत है निर्माता। दिशानिर्देश: यदि आपको डेटा की अपनी प्रति की आवश्यकता है, तो उस प्रतिलिपि को पैरामीटर सूची में बनाएं; यह कॉलर और कंपाइलर को प्रतिलिपि बनाने या स्थानांतरित करने का निर्णय सक्षम बनाता है।

+1

इसलिए पहला उदाहरण काम करने का कारण यह है कि टी 1 वास्तव में 'शून्य फू (कॉन्स std :: string & & arg arg) के बराबर हल हो जाता है, जो संदर्भ का उपयोग करके 'शून्य foo (const std :: string और arg)' तक कम हो जाता है कटौती नियम? यह उदाहरण 2 में विफल रहता है क्योंकि स्ट्रिंग के लिए कोई लेल्यू ओवरलोड नहीं है? क्या टेम्पलेट फ़ंक्शन को परिभाषित करने के लिए कोई सर्वोत्तम प्रथाएं हैं ताकि कम से कम अपेक्षाकृत स्पष्ट हो कि प्रकार क्या होना चाहिए? आदर्श रूप से मैं 2^एन ओवरलोड से बचते समय इस प्रकार के साथ स्पष्ट होने का एक अच्छा तरीका ढूंढ रहा हूं। – Mranz

+1

@Mranz: निश्चित रूप से। अच्छा, तुम किसके लिए जा रहे हो? अग्रेषण और टेम्पलेट का उपयोग अग्रेषण के लिए किया जाना है, आपको वास्तव में प्रकारों को जानने की आवश्यकता नहीं है। – GManNickG

+0

चलें कहते हैं कि मैं एक निर्माता है कि एक वेक्टर तरह 'क्लास (.. कुछ args ..., वेक्टर आइटम)' में लेता है। आदर्श रूप में, मैं उस तर्क के लिए अनुमति देना चाहता हूं कि प्रतिलिपि अर्थशास्त्र का उपयोग करके प्रतिलिपि से बचें या एक रावल्यू हो। इसका समर्थन करने के लिए, मुझे या तो आइटम को टेम्पलेट करना होगा, या एक रावल्यू अधिभार बनाना होगा। यदि मैं इसे टेम्पलेट करता हूं, तो वास्तविक प्रकार परिभाषा पर खो जाता है, और हेडर फ़ाइल या कुछ टिप्पणी पढ़कर वास्तविक तर्क को मेरी कक्षा के उपभोक्ताओं द्वारा घटाया जाना चाहिए। – Mranz

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