2015-03-21 10 views
6

में tuple तत्वों के प्रकार को कम करें मेरे पास निम्न कोड है।सी ++ 11

template <typename... Types> 
void print_tuple(const std::tuple<Types&&...>& value) 
{ 
    std::cout << std::get<0>(value) << "," << std::get<1>(value) << std::endl; 
} 
print_tuple(std::forward_as_tuple("test",1)); 
जो संकलक

शिकायत के बारे में

error: invalid initialization of reference of type ‘const std::tuple<const char (&&)[5], int&&>&’ from expression of type ‘std::tuple<const char (&)[5], int&&>’ 
    print_tuple(std::forward_as_tuple("test",1)); 

क्यों संकलक टपल में पहली तत्व के प्रकार अनुमान है स्थिरांक चार होने के लिए (& &) [5]?

+0

आपको विशेष रूप से टुपल को कैप्चर करने की भी आवश्यकता नहीं है। क्यों न केवल 'टेम्पलेट शून्य प्रिंट_टुपल (टुपल और मूल्य) '? – 0x499602D2

+0

चूंकि यह कम से कम दो लोगों के लिए स्पष्ट नहीं था: आपकी 'print_tuple' परिभाषा * करता है * कॉल को अनुमति देता है अगर टेम्पलेट तर्क स्पष्ट रूप से 'print_tuple ' के रूप में निर्दिष्ट किए जाते हैं। यह एक अच्छा सवाल है कि संकलक पहले 'प्रकार' को अलग-अलग क्यों कम कर रहा है। – hvd

+0

@hvd ऐसा इसलिए हो सकता है क्योंकि एक स्ट्रिंग अक्षर एक लवल है और इसे अग्रेषित किया जा रहा है। – 0x499602D2

उत्तर

2

आम तौर पर सफल होने के लिए कटौती के लिए, तर्क को पैरामीटर के समान सामान्य रूप की आवश्यकता होती है। कुछ अपवाद हैं जहां T &&U & (T = U & चुनकर) से लिया जा सकता है, लेकिन इस मामले के लिए ऐसा कोई अपवाद निर्दिष्ट नहीं किया गया था।

14.8.2.5 एक प्रकार से टेम्पलेट तर्क बात का अनुमान लगाना [temp.deduct.type]

8 एक टेम्पलेट प्रकार तर्क T, एक टेम्पलेट टेम्पलेट तर्क TT या एक टेम्पलेट गैर प्रकार तर्क i हो सकता है निष्कर्ष निकाला है, तो P और A निम्नलिखित रूपों में से एक है:

[...]

T&
T&&

[...]

यह बिल्कुल स्पष्ट नहीं है, लेकिन इस P (पैरामीटर) और A (तर्क) की आवश्यकता है दोनों को एक ही रूप है। उन्हें T& फॉर्म, या दोनों T&& फ़ॉर्म दोनों की आवश्यकता है।अपवाद, जिन परिस्थितियों में T &&U & से निष्कर्ष निकाला जा सकता है, मिलान से पहले सादा T करने के लिए T && बदलते द्वारा किया जाता है जगह लेता है, सीमित परिस्थितियों में:

10 इसी प्रकार, यदि P एक रूप है कि (T) शामिल है, तो संबंधित पैरामीटर प्रकार सूची P की से प्रत्येक पैरामीटर प्रकार Pi इसी पैरामीटर प्रकार इसी पैरामीटर प्रकार सूची A की की Ai साथ तुलना में है। यदि P और A कार्य प्रकार हैं जो किसी फ़ंक्शन टेम्पलेट (14.8.2.2) का पता लेते समय कटौती से उत्पन्न होते हैं या फ़ंक्शन घोषणा (14.8.2.6) और Pi और Ai से टेम्पलेट तर्कों को कम करते समय शीर्ष-स्तर के पैरामीटर होते हैं पैरामीटर प्रकार सूची P और A की क्रमश: Pi अगर यह एक सीवी-अयोग्य टेम्पलेट पैरामीटर के लिए एक rvalue संदर्भ और Ai एक lvalue संदर्भ, जिस स्थिति में Pi के प्रकार के टेम्पलेट में परिवर्तित हो जाता है निकाला जाता है पैरामीटर प्रकार (यानी, T&& को T में बदला गया है)। [...]

और

14.8.2.1 एक समारोह कॉल [temp.deduct.call]

3 [...] तो P है से टेम्पलेट तर्क बात का अनुमान लगाना एक सीवी-अयोग्य टेम्पलेट पैरामीटर का एक रेवल्यू संदर्भ और तर्क एक लवल्यू है, प्रकार A "के प्रकार का उपयोग" A "के प्रकार का उपयोग प्रकार के कटौती के लिए A के स्थान पर किया जाता है। [...]

लेकिन आपके परिदृश्य पर कोई भी अपवाद लागू नहीं होता है।

यह इस एक ही सिद्धांत है कि renders है

template <typename T> struct S { }; 
template <typename T> void f(S<const T>) { } 
int main() { f(S<void()>()); } 

अमान्य: const T, void() से निष्कर्ष निकाला नहीं जा सकता है, भले ही T = void() वास्तव में परिणाम देना होगा, और बुला f<void()> कामयाब होने की।

Wintermute के नष्ट कर दिया जवाब से पता चला कि आप

template <typename... Types>  // vv-- change here 
void print_tuple(const std::tuple<Types...>& value) 

बजाय का उपयोग कर सकते हैं: इस Types lvalue संदर्भ के रूप में निष्कर्ष निकाला जा करने के लिए अनुमति देता है, rvalue संदर्भ के रूप में, या गैर संदर्भ, के प्रकार के आधार के रूप में value

0

क्या आप &&std::tuple<Types&&...> में सार्वभौमिक संदर्भ के रूप में उपयोग करना चाहते थे? यह सार्वभौमिक संदर्भ नहीं है; यह rvalue संदर्भ है और केवल rvalues ​​से बांध सकते हैं।

template<typename T> 
class TD; 

फिर अपने टेम्पलेट समारोह को परिभाषित:

implicit instantiation of undefined template 'TD<const std::__1::tuple<std::__1::basic_string<char> &&, int &&> &>' 

:

template <typename... Types> 
void print_tuple(const std::tuple<Types&&...>& value) 
{ 
    TD<decltype(value)> a; 
    std::cout << std::get<0>(value) << "," << std::get<1>(value) << std::endl; 
} 

तो फिर तुम जैसे संकलन त्रुटि देखेंगे आप संदर्भ की किस तरह यह है की जाँच करने के इस तरह कर सकते हैं आप देख सकते हैं कि int प्रकार के लिए भी, यह rvalue संदर्भ होने के लिए deduces। रावल संदर्भ संदर्भों से बंधे नहीं जा सकते हैं। आपको लगता है कि कोशिश कर सकते हैं फोन करके:

int i = 1; 
print_tuple(std::forward_as_tuple(i,1)); // error. 

इसलिए, यह सही है कि const char(&&)[5] निष्कर्ष निकाला जाता है, और एक स्ट्रिंग शाब्दिक const char(&&)[5] में परिवर्तित नहीं किया जा सकता है। यदि आप print_tuple पर कॉल करते हैं:

print_tuple(std::forward_as_tuple(string("test"),1)); 

यह काम करेगा। अब प्रकार tuple<string&&, int&&> है।

+0

जैसा कि मैंने प्रश्न पर टिप्पणी की, अगर स्पष्ट रूप से टेम्पलेट तर्कों को वर्तनी देता है, जैसा कि 'print_tuple 'में है, यह काम करता है। यह जवाब गलत है। 'T &&' अनिवार्य रूप से एक रावल्यू संदर्भ नहीं है। यदि 'टी' एक लाभार्थी संदर्भ है, तो' T && 'केवल' टी' है। एकमात्र समस्या यह है कि कटौती काम नहीं कर रही है: जब 'टी एंड' '' यू ''माना जाता है, तो' टी' 'यू 'के रूप में नहीं लिया जा रहा है, भले ही यह हो। – hvd

+0

@hvd भाषा में कुछ भी नहीं है जो कहता है कि इस संदर्भ में 'टी' को 'यू 'के रूप में घटाया जा सकता है। [Temp.deduct.call]/3 के लिए शर्तें पूरी नहीं हुई हैं। एक सरल उदाहरण है 'टेम्पलेट शून्य एफ (कॉन्स टी एंड कॉम)' जो कि अंतराल से बंधे नहीं होगा। बेशक आप स्पष्ट रूप से टेम्पलेट का विशेषज्ञ नहीं हैं, जो टेम्पलेट तर्क कटौती के बारे में किसी प्रश्न में वास्तव में प्रासंगिक नहीं है। – Oktalist

+0

@ ऑक्टालिस्ट इसे टेम्पलेट को विशेषज्ञता देने की आवश्यकता नहीं है। इसे केवल टेम्पलेट तर्क निर्दिष्ट करने की आवश्यकता है। आप 'f 'को किसी भी समस्या के बिना' int 'lvalue अभिव्यक्ति के साथ कॉल कर सकते हैं, भले ही कटौती आपको' टी = int '' नहीं देगी। मैंने अभी कुछ और विवरणों के साथ एक उत्तर पोस्ट किया है। – hvd