2010-04-10 15 views
26

मैं निम्नलिखित प्राप्त करने के लिए टेम्पलेट कटौती का उपयोग करने में सक्षम होना चाहता हूं:अपने रिटर्न प्रकार के आधार पर फ़ंक्शन के लिए टेम्पलेट कटौती?

GCPtr<A> ptr1 = GC::Allocate(); 
GCPtr<B> ptr2 = GC::Allocate(); 

इसके बजाय (मेरे पास वर्तमान में क्या है):

GCPtr<A> ptr1 = GC::Allocate<A>(); 
GCPtr<B> ptr2 = GC::Allocate<B>(); 

मेरा वर्तमान आवंटन फ़ंक्शन इस तरह दिखता है:

class GC 
{ 
public: 
    template <typename T> 
    static GCPtr<T> Allocate(); 
}; 

अतिरिक्त < ए> और < बी> को बंद करना संभव होगा?

धन्यवाद

+0

fwiw मेरे पास कुछ समान था लेकिन कन्स्ट्रक्टर तर्कों के प्रकार के आधार पर रिटर्न प्रकार के साथ। मैंने एक templated सहायक समारोह 'make_complex_template_obj (the args)' बनाया है, इसलिए मैं उस func से चर को init'ing जब 'ऑटो' का उपयोग कर सकते हैं। संभावित रूप से स्वीकार्य उत्तर के समान कारण के लिए, उस टेम्पलेट को 'ऑटो' रिटर्न प्रकार नहीं दिया जा सका। शुक्र है कि मैं 'रिटर्न' में टाइपनाम को डुप्लिकेट करने से बच सकता था, तब तक यह पता था कि किस प्रकार का आ रहा था और एक बेयर _initialiser-list_ को उचित रूप से परिवर्तित किया गया था। काफी रोमांच! –

उत्तर

28

ऐसा नहीं किया जा सकता है। रिटर्न टाइप टाइप कटौती में हिस्सा नहीं लेता है, बल्कि यह उचित टेम्पलेट हस्ताक्षर से पहले से मेल खाने का नतीजा है।

// helper 
template <typename T> 
void Allocate(GCPtr<T>& p) { 
    p = GC::Allocate<T>(); 
} 

int main() 
{ 
    GCPtr<A> p = 0; 
    Allocate(p); 
} 

चाहे कि वाक्य रचना वास्तव में किसी भी अच्छा है या प्रारंभिक GCPtr<A> p = GC::Allocate<A>() से बदतर है एक और सवाल यह है: आप, फिर भी, इसे के रूप में ज़्यादातर उपयोग से छुपा सकते हैं।

पीएस सी ++ 11 आपको एक प्रकार की घोषणाओं को छोड़ने की अनुमति देगा:

auto p = GC::Allocate<A>(); // p is of type GCPtr<A> 
0

आप इसके लिए मैक्रो का उपयोग करने का प्रयास कर सकते हैं। इसके अलावा, मैं नहीं देखता कि इसे केवल एक कथन के साथ कैसे काम करना चाहिए।

#define ALLOC(ptrname,type) GCPtr<type> ptrname = GC::Allocate<type>() 

ALLOC(ptr1,A); 

जोहान्स के अंक मान्य हैं। >> मुद्दा आसानी से तय किया गया है। विस्तार varargs लेकिन मैं होने के लिए अल्पविराम लगता है के रूप में प्रकार का हिस्सा C99 पूर्वप्रक्रमक की आवश्यकता है:

#define ALLOC(ptrname,...) GCPtr<__VA_ARGS__> ptrname = GC::Allocate<__VA_ARGS__>() 

ALLOC(ptr1,SomeTemplate<int,short>); 
+1

ध्यान दें कि यदि आप 'ALLOC (ptr1, ए ) करते हैं तो यह मैक्रो विफल हो जाता है;' (दो समस्याएं हैं: 'प्रकार' (उर्फ ''' ') के बाद कोई स्थान नहीं और अल्पविराम' ए 'से दो मैक्रो तर्क बनाता है ')। –

+0

और वह आपको क्या खरीदेंगे? आपको अभी भी इस प्रकार का उल्लेख करना होगा, और यह एक इनलाइन फ़ंक्शन टेम्पलेट के साथ डेविड के समाधान से कम सुरक्षित है। -1 मुझसे – sbi

+0

आप 'ALLOC (ptr1, (ए )) कहकर दोनों समस्याओं को हल कर सकते हैं;' और फ़ंक्शन-प्रकार को 'टेम्पलेट स्ट्रक्चर टाइ' में पास करने के लिए मैक्रो को फिर से लिखना; टेम्पलेट संरचना ty {टाइपपीफ टाइप प्रकार; }; 'और' GCPtr :: इसके बजाय टाइप करें> ptrname' टाइप करें (और टेम्पलेट्स के भीतर उपयोग के लिए 'टाइपनाम' के साथ ही। C++ 0x और कुछ वर्तमान C++ 03 कंपाइलर्स 'टाइपनाम' को टेम्पलेट के बाहर भी अनुमति देता है , हालांकि)। –

1

उसी तरह आप वापसी प्रकार पर कार्य करता है ओवरलोड नहीं कर सकता है, तो आप उस पर कटौती टेम्पलेट नहीं कर सकते। और इसी कारण से - अगर च() एक टेम्पलेट/अधिभार कि कुछ देता है, किस प्रकार का उपयोग करने के लिए यहाँ:

f(); 
+1

ठीक है मैंने पहले ही इसके बारे में सोचा है। मेरा कचरा कलेक्टर क्लास संदर्भ गिनती का उपयोग करता है, और जीसी :: आवंटन() को कॉल करने के लिए स्वाभाविक रूप से 0 संदर्भ होंगे जो वैसे भी साफ हो जाएंगे। यह निश्चित रूप से है यदि कोड संकलित/ – Marlon

+2

संकलक त्रुटि, जब तक कि एक कलाकार ('(int) f();') में दिखाई नहीं दे रहा है ...? – UncleBens

+0

@UncleBens: अच्छा विचार! हालांकि, सी ++ कंपाइलर वर्तमान में इस तरह से काम नहीं करता है। – Vlad

18

केवल एक चीज मैं के बारे में सोच सकते हैं: एक गैर टेम्पलेट है कि एक गैर रिटर्न का आवंटन करना -टेम्प्लेट प्रॉक्सी ऑब्जेक्ट जिसमें एक टेम्पलेटेड रूपांतरण ऑपरेटर है जो वास्तविक कार्य करता है:

template <class T> 
struct GCPtr 
{ 

}; 

class Allocator 
{ 
public: 
    template <class T> 
    operator GCPtr<T>() { return GCPtr<T>(); } 
}; 

class GC 
{ 
public: 
    static Allocator Allocate() { return Allocator(); }//could give a call-back pointer? 
}; 

int main() 
{ 
    GCPtr<int> p = GC::Allocate(); 
} 
+2

यह बहुत अधिक लगता है, लेकिन फिर भी, मैंने नहीं किया इस पैटर्न को जानें। आपने मुझे कुछ सिखाया। तो +1। – paercebal

+0

वैसे भी, पहली नज़र में, मुझे लगता है कि आप जीसी :: आवंटन() से पूरी तरह से बच सकते हैं और लिख सकते हैं: 'जीसीपीआर पी = आवंटक();', नहीं? – paercebal

+1

जैसा कि टिप्पणी कहती है, ऑलोकेटर ऑब्जेक्ट कन्स्ट्रक्टर के माध्यम से प्राप्त होने वाले अतिरिक्त डेटा को स्टोर कर सकता है, इसलिए जीसी :: आवंटन यह तय कर सकता है कि ऑपरेशन के लिए उसे किस डेटा की आवश्यकता है। - आखिरकार ' जीसीपीआर 'काम स्वयं ही कर सकता है (' जीसी :: आवंटित ') का आह्वान करें। – UncleBens

7

आप विपरीत मार्ग पर जा सकते हैं।

आप (कुछ दिनों के, या जीसीसी के वर्तमान संस्करण में बाहर किया जाना चाहिए जो MSVC 2010) और C++ 0x सुविधाओं पर निर्भर कोई आपत्ति नहीं है तारीख संकलक अप करने के लिए एक प्रयोग कर रहे हैं:

auto ptr1 = GC::Allocate<A>(); 
auto ptr2 = GC::Allocate<B>(); 

आपको अतिरिक्त <A> और <B> बचाएगा, बस दाईं तरफ नहीं। :)

4

(इस उत्तर @UncleBens के रूप में ही थोड़ा अधिक सामान्य यह सही-आगे कोई भी तर्क रूप में है, लेकिन।)

यह haskell जैसी भाषाओं में जहां बहुत उपयोगी है, उदाहरण के लिए, read ले जाएगा एक स्ट्रिंग इनपुट के रूप में और इच्छित वांछित प्रकार के अनुसार इसे पार्स करेगा।

(यहाँ sample code on ideone है।)

सबसे पहले, समारोह foo जिसका वापसी प्रकार हम अनुमान करना चाहते हैं के साथ शुरू:

template<typename Ret> 
Ret foo(const char *,int); 
template<> 
std::string foo<std::string>(const char *s,int) { return s; } 
template<> 
int   foo<int  >(const char *,int i) { return i; } 

जब एक स्ट्रिंग के लिए कहा है, यह स्ट्रिंग में है कि वापस आ जाएंगे, इसका पहला तर्क जब एक int के लिए पूछा जाता है, तो यह दूसरा तर्क वापस कर देगा।

हम एक समारोह auto_foo कि के रूप में इस्तेमाल किया जा सकता परिभाषित कर सकते हैं इस प्रकार है:

int main() { 
     std::string s = auto_foo("hi",5); std::cout << s << std::endl; 
     int   i = auto_foo("hi",5); std::cout << i << std::endl; 
} 

इस काम बनाने के लिए हम एक वस्तु को अस्थायी रूप से समारोह तर्क स्टोर करेगा, और यह भी समारोह जब चलाने की जरूरत है यह वांछित वापसी प्रकार के convert करने के लिए कहा जाता है:

#include<tuple> 

template<size_t num_args, typename ...T> 
class Foo; 
template<typename ...T> 
class Foo<2,T...> : public std::tuple<T&&...> 
{ 
public: 
     Foo(T&&... args) : 
       std::tuple<T&&...>(std::forward<T>(args)...) 
     {} 
     template< typename Return > 
     operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this)); } 
}; 
template<typename ...T> 
class Foo<3,T...> : std::tuple<T&&...> 
{ 
public: 
     Foo(T&&... args) : 
       std::tuple<T&&...>(std::forward<T>(args)...) 
     {} 
     template< typename Return > 
     operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this), std::get<2>(*this)); } 
}; 

template<typename ...T> 
auto 
auto_foo(T&&... args) 
     // -> Foo<T&&...> // old, incorrect, code 
     -> Foo< sizeof...(T), T&&...> // to count the arguments 
{ 
     return    {std::forward<T>(args)...}; 
} 

इसके अलावा, दो आर्ग या तीन आर्ग कार्यों के लिए ऊपर काम करता है, है ना मुश्किल देखने के लिए है इसका विस्तार कैसे करें।

यह लिखने के लिए बहुत सी कोड है! प्रत्येक फंक्शन के लिए आप इसे लागू करेंगे, आप एक मैक्रो लिख सकते हैं जो आपके लिए यह करता है। आपकी फ़ाइल के ऊपरी भाग पर कुछ इस तरह:

REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares 
         // necessary structure and auto_??? 

और फिर आप अपने कार्यक्रम में auto_foo इस्तेमाल कर सकते हैं।

+0

मुझे यह काफी दिलचस्प लगता है, लेकिन मेरा मानना ​​है कि आप auto_foo में विशेषज्ञता पैरामीटर खो रहे हैं: 'auto auto_foo (T && ... args) -> Foo ', क्योंकि अन्यथा यह विशेषज्ञता आईएमएचओ का चयन नहीं करेगा। – daminetreg

+0

आप सही हैं। मैं यहां कोड अपडेट करूंगा। मैंने अपने कंप्यूटर पर कोड का परीक्षण किया था, लेकिन जाहिर है मैंने इसे बिल्कुल कॉपी नहीं किया था। धन्यवाद! –

+0

किसी भी मामले में यह इसे लागू करने का एक अच्छा तरीका है। उदाहरण के लिए धन्यवाद। – daminetreg

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