2010-04-19 14 views
23

के लिए एक वापसी प्रकार के निर्माण यह शायद एक बहुत आसानी से समझा जा रहा है, लेकिन मैं मैं गलत हूँ मामले में जितना संभव हो उतना पृष्ठभूमि की कहानी देने के लिए जा रहा हूँ। इतना verbose होने के लिए उन्नत माफी। मैं gcc4.5 का उपयोग कर रहा हूं, और मुझे एहसास है कि सी ++ 0 एक्स समर्थन अभी भी कुछ हद तक प्रयोगात्मक है, लेकिन मैं इस धारणा पर कार्य करने जा रहा हूं कि व्यवहार के लिए एक गैर-बग से संबंधित कारण है।अजीब व्यवहार जब रिकर्सिवली variadic कार्यों

मैं variadic समारोह टेम्पलेट्स के साथ प्रयोग कर रहा हूँ। अंतिम लक्ष्य std::pair से एक विपक्ष सूची बनाना था। यह एक कस्टम प्रकार, केवल जोड़ी वस्तुओं की एक स्ट्रिंग होने का मतलब नहीं था। सूची जो संरचना का निर्माण करती है उसे रिकर्सिव कॉल के परिणाम पर निर्भर होने पर अंतिम वापसी मूल्य पर निर्भर होना चाहिए। एक जोड़ा मोड़ के रूप में, सूची में डालने से पहले लगातार पैरामीटर जोड़े गए हैं। तो अगर मैं [1, 2, 3, 4, 5, 6] पास करता हूं तो अंतिम परिणाम {1 + 2, {3 + 4, 5 + 6}} होना चाहिए।

मेरा प्रारंभिक प्रयास काफी मूर्ख था। दो ओवरलोड के साथ एक समारोह, बिल्ड। एक ने दो समान पैरामीटर लिया और बस अपना योग वापस कर दिया। दूसरे ने दो पैरामीटर और पैरामीटर पैक लिया। रिटर्न वैल्यू एक जोड़ी थी जिसमें दो सेट पैरामीटर और रिकर्सिव कॉल की राशि शामिल थी। पूर्व-निरीक्षण में, यह स्पष्ट रूप से एक दोषपूर्ण रणनीति थी, क्योंकि जब मैं अपने रिटर्न प्रकार को समझने की कोशिश करता हूं तो फ़ंक्शन घोषित नहीं किया जाता है, इसलिए इसमें गैर-पुनरावर्ती संस्करण को हल करने के अलावा कोई विकल्प नहीं है।

जो मैं समझता हूं। जहां मैं भ्रमित हो गया वह दूसरा पुनरावृत्ति था। मैंने उन कार्यों को टेम्पलेट वर्ग के स्थिर सदस्यों को बनाने का निर्णय लिया। फ़ंक्शन कॉल स्वयं पैरामीटरकृत नहीं हैं, बल्कि इसकी पूरी कक्षा है। मेरी धारणा यह थी कि जब रिकर्सिव फ़ंक्शन अपने रिटर्न प्रकार को उत्पन्न करने का प्रयास करता है, तो यह संरचना के एक नए संस्करण को अपने स्थिर कार्य के साथ तुरंत चालू कर देगा, और सब कुछ स्वयं ही काम करेगा।

परिणाम था:

अपमानजनक कोड: "त्रुटि BuildStruct<double, double, char, char>::Go(const char&, const char&) करने के लिए कॉल के लिए कोई मिलता-जुलता समारोह":

static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
    -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 

मेरे भ्रम तथ्य यह है कि BuildStruct पैरामीटर हमेशा एक ही होना चाहिए से आता है BuildStruct::Go पर भेजे गए तर्कों के प्रकार, लेकिन त्रुटि कोड में प्रारंभिक दो डबल पैरामीटर गुम हैं। मुझे यहां क्या समझ नहीं आ रहा है? यदि स्थाई कार्यों का चयन करने के बारे में मेरी प्रारंभिक धारणा गलत थी, तो फ़ंक्शन खोजने के बजाए गलत फ़ंक्शन को कॉल करने का प्रयास क्यों किया जा रहा है? ऐसा लगता है कि मिश्रण प्रकारों की तरह दिखने लगते हैं, और मैं सिर्फ एक स्पष्टीकरण के साथ क्यों नहीं आ सकता हूं। यदि मैं प्रारंभिक कॉल में अतिरिक्त पैरामीटर जोड़ता हूं, तो यह हमेशा असफल होने से पहले उस अंतिम चरण तक गिर जाता है, इसलिए संभावित रूप से रिकर्सन कम से कम आंशिक रूप से काम कर रहा है। यह प्रारंभिक प्रयास के विपरीत है, जो हमेशा फ़ंक्शन कॉल को ढूंढने में असफल रहा।

अंत में, मैं एक काफी सुरुचिपूर्ण समाधान है कि शायद ही पहले दो प्रयासों में से या तो जैसा दिखता है के साथ, समस्या अतीत मिल गया है। तो मुझे पता है कि मैं क्या करना चाहता हूं। मैं देखे गए विफलता के लिए एक स्पष्टीकरण की तलाश में हूं।

पूर्ण कोड का पालन करने के बाद मुझे यकीन है कि मेरे मौखिक विवरण अपर्याप्त था हूँ। पहले कुछ बॉयलरप्लेट, यदि आप कोड निष्पादित करने के लिए मजबूर महसूस करते हैं और इसे अपने लिए देखते हैं। फिर प्रारंभिक प्रयास, जो उचित रूप से विफल रहा, फिर दूसरा प्रयास, जो नहीं था।

#include <iostream> 
using std::cout; 
using std::endl; 

#include <utility> 

template<typename T1, typename T2> 
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) { 
    return str << "[" << p.first << ", " << p.second << "]"; 
} 

//Insert code here  

int main() { 
    Execute(5, 6, 4.3, 2.2, 'c', 'd'); 
    Execute(5, 6, 4.3, 2.2); 
    Execute(5, 6); 

    return 0; 
} 

गैर struct समाधान:

template<typename Type> 
Type BuildFunction(const Type& t0, const Type& t1) { 
    return t0 + t1; 
} 

template<typename Type, typename... Rest> 
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest) 
     -> std::pair<Type, decltype(BuildFunction(rest...))> { 
    return std::pair<Type, decltype(BuildFunction(rest...))> 
        (t0 + t1, BuildFunction(rest...)); 
} 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildFunction(t...) << endl; 
} 

परिणामस्वरूप त्रुटियों:

test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:33:35: instantiated from here 
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)' 

Struct समाधान:

template<typename... Types> 
struct BuildStruct; 

template<typename Type> 
struct BuildStruct<Type, Type> { 
    static Type Go(const Type& t0, const Type& t1) { return t0 + t1; } 
}; 

template<typename Type, typename... Types> 
struct BuildStruct<Type, Type, Types...> { 
    static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
     -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> { 
    return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 
       (t0 + t1, BuildStruct<Types...>::Go(rest...)); 
    } 
}; 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildStruct<Types...>::Go(t...) << endl; 
} 

परिणामस्वरूप त्रुटियों:

test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>': 
test.cpp:33:3: instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]' 
test.cpp:38:41: instantiated from here 
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)' 
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char] 
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:38:41: instantiated from here 
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>' 
+0

अभी यह कोशिश नहीं कर सकता है लेकिन यह हो सकता है कि स्थगित वापसी प्रकार की कटौती अभी भी विफल हो रही है। दूसरे मामले में आपको रिटर्न टाइप टाइप करने में सक्षम होना चाहिए: 'typedef std :: pair <टाइप, टाइपनाम बिल्डस्ट्रक्चर :: result_type> result_type;' (और उपयुक्त विशेषज्ञता के लिए उपयुक्त) और उन का उपयोग करें: 'static result_type go (...); ' – visitor

+0

मुझे लगता है कि मैंने कोशिश की, लेकिन परिणाम याद नहीं है। जब मैं घर जाता हूं तो मैं इसे एक और शॉट दूंगा। धन्यवाद। –

+31

अच्छा भगवान, यह * पढ़ने के लिए बहुत कुछ है :) –

उत्तर

2

टिप्पणियां पढ़ना, यह पर्याप्त स्पष्ट लगता है कि यह G ++ के किसी विशेष संस्करण में एक बहुत ही स्थानीय बग है, और यह सब जवाब कभी भी होगा।

+0

मैं एक महीने पहले उस निष्कर्ष पर पहुंचा, जवाब देने के लिए धन्यवाद ताकि मैं इसे दूर कर सकूं :) –

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