2010-04-13 20 views
10

साथ निर्माता, एक टेम्पलेट समारोह है कि उदाहरण के लिए तर्क के परिवर्तनशील लेता है, बनाने के लिए इस Vector< T, C > वर्ग निर्माता में क्या यह संभव है:सी ++ खाका कक्षा चर तर्क

template < typename T, uint C > 
Vector< T, C >::Vector(T, ...) 
{ 
    va_list arg_list; 
    va_start(arg_list, C); 
    for(uint i = 0; i < C; i++) { 
     m_data[ i ] = va_arg(arg_list, T); 
    } 
    va_end(arg_list); 
} 

यह लगभग काम करता है, लेकिन अगर किसी को कॉल Vector< double, 3 >(1, 1, 1), केवल पहले तर्क में सही मान है। मुझे संदेह है कि पहला पैरामीटर सही है क्योंकि इसे फंक्शन कॉल के दौरान double पर डाला जाता है, और अन्य को int एस के रूप में व्याख्या किया जाता है और फिर बिट्स को double में भर दिया जाता है। कॉलिंग Vector< double, 3 >(1.0, 1.0, 1.0) वांछित परिणाम देता है। क्या ऐसा कुछ करने का कोई पसंदीदा तरीका है?

+2

ध्यान दें कि सी ++ 11 के सार्वभौमिक प्रारंभकर्ता वाक्य रचना आप एक सुरक्षित तरीके से इस दे देंगे के लिए अवैध रूप से बुला सम्मेलन। – sbi

उत्तर

2

इस कोड को खतरनाक लग रहा है और मुझे लगता है कि क्यों यह काम नहीं कर रहा पर अपना विश्लेषण स्थान पर है, वहाँ के लिए संकलक पता चला है कि जब बुला कोई रास्ता नहीं है:

Vector< double, 3 >(1, 1, 1) 

वाले युगल के रूप में पारित किया जाना चाहिए ।

मैं की तरह कुछ करने के लिए निर्माता बदल जाएगा:

Vector< T, C >::Vector(const T(&data)[C]) 
बजाय

, और उपयोगकर्ता एक सरणी के रूप में तर्क पारित किया है। बदसूरत समाधान का एक अन्य प्रकार कुछ इस तरह होगा:

template < typename T, uint C > 
Vector< T, C >::Vector(const Vector<T, C - 1>& elements, T extra) { 
} 

और इस तरह इसे कहते हैं (कुछ typedefs के साथ):

Vector3(Vector2(Vector1(1), 1), 1); 
+2

या 'टी (और डेटा) [सी] 'और उपयोगकर्ता संदर्भ के अनुसार एक सरणी के रूप में तर्क पास करता है। यह कम लचीला है क्योंकि यह गतिशील सरणी के उपयोग की अनुमति नहीं देता है, लेकिन यह तर्कों की सही संख्या को लागू करने में मदद कर सकता है। –

+0

@ क्रिस अच्छा बिंदु –

+2

इसके अलावा, अपने दूसरे सुझाव के साथ, 'सी = 0' और/या 'सी = 1' के लिए टेम्पलेट का विशेषज्ञ बनाना सुनिश्चित करें। –

0

C++ 0x (वास्तव में सी ++ 1x बुलाया जाना चाहिए), तो आप टेम्पलेट का उपयोग कर सकते हैं प्राप्त करने के लिए एक typesafe में आप क्या चाहते हैं varargs में फैशन (और आपको तर्कों की संख्या निर्दिष्ट करने की भी आवश्यकता नहीं होगी!)। हालांकि, सी ++ के मौजूदा संस्करण (2003 संशोधन के साथ आईएसओ सी ++ 1998) में, जो भी आप चाहते हैं उसे पूरा करने का कोई तरीका नहीं है। बूस्ट करता है या जो बूस्ट करता है, वह preprocessor macro magic का उपयोग कर सकता है ताकि कन्स्ट्रक्टर की परिभाषा को कई बार पैरामीटर को हार्ड-कोडित, लेकिन बड़ी सीमा तक दोहराया जा सके। यह देखते हुए कि Boost.Preprocessor तरह का उलझी है, तो आप बस अपने आप निम्न में से सभी को परिभाषित कर सकते हैं:

 
Vector<T,C>::Vector(); 
Vector<T,C>::Vector(const T&); 
Vector<T,C>::Vector(const T&, const T&); 
// ... 

ऊपर के बाद से दर्दनाक तरह के हाथ से करना है, हालांकि, आप एक स्क्रिप्ट यह उत्पन्न करने के लिए लिख सकते हैं।

+2

हर कोई जानता है कि "एक्स" हेक्साडेसिमल अंक है ;-) –

9

ओह, अभी वहाँ यह करने के लिए कोई अच्छा तरीका है। बूस्ट संकुल इस तरह बातें परिभाषित करने के लिए कुछ इसी तरह के प्रयोग मैक्रो चाल क्या करने की जरूरत है कि में से अधिकांश:

template < typename T > 
Vector<T>::Vector(T) 
{ ... } 

template < typename T, uint C > 
Vector< T, C >::Vector(T t, C c1) 
{ ... } 

template < typename T, uint C > 
Vector< T, C >::Vector(T t, C c1, C c2) 
{ ... } 

template < typename T, uint C > 
Vector< T, C >::Vector(T t, C c1, C c2, C c3) 
{ ... } 

मैक्रो कुछ निर्धारित संख्या (आमतौर पर 10 के आसपास) संस्करणों उत्पन्न, और एक तंत्र प्रदान की अधिकतम संख्या को बदलने के लिए निर्माण का विस्तार करने से पहले पैरामीटर।

असल में, इसका वास्तविक दर्द यही कारण है कि सी ++ 0x परिवर्तनीय-लंबाई टेम्पलेट तर्क और प्रतिनिधिमंडल विधियों को पेश कर रहा है जो आपको यह स्पष्ट रूप से (और सुरक्षित रूप से) करने देगा। इस बीच आप या तो मैक्रोज़ के साथ ऐसा कर सकते हैं, या एक सी ++ कंपाइलर आज़मा सकते हैं जिसमें इन नई प्रयोगात्मक सुविधाओं (कुछ) के लिए समर्थन है। इसके लिए जीसीसी एक अच्छा है।

चेतावनी दी जानी चाहिए कि चूंकि सी ++ 0x वास्तव में अभी तक बाहर नहीं है, इसलिए चीजें अभी भी बदल सकती हैं और आपका कोड मानक के अंतिम संस्करण के साथ समन्वयित नहीं हो सकता है। इसके अलावा, मानक आने के बाद भी, 5 साल या उससे भी कम समय के दौरान कई कंपाइलर्स केवल आंशिक रूप से मानक का समर्थन करेंगे, इसलिए आपका कोड बहुत पोर्टेबल नहीं होगा।

+0

यदि आप मैक्रो तरीके से नीचे जाते हैं तो बूस्ट.प्रप्रोसेसर देखें। 'BOOST_PP_REPEAT' और 'BOOST_PP_ENUM_TRAILING_PARAMS' को संचयी करना आपको सही रास्ते पर सेट करना चाहिए। –

+0

धन्यवाद। जब मैं उपरोक्त पोस्ट करता था तो मैं जल्दी में था, इसलिए मैं बूस्ट प्रीप्रोसेसर मैक्रोज़ क्या देख रहा था। – swestrup

2

आप जो भी चाहते हैं वह कर सकते हैं, लेकिन ऐसा न करें, क्योंकि यह टाइपएफ़ नहीं है। सर्वश्रेष्ठ T का वेक्टर पास करें या उन मानों वाले इटरेटर की एक जोड़ी।

template < typename T, uint C > 
Vector< T, C >::Vector(int N, ...) 
{ 
    assert(N < C && "Overflow!"); 
    va_list arg_list; 
    va_start(arg_list, N); 
    for(uint i = 0; i < N; i++) { 
     m_data[i] = va_arg(arg_list, T); 
    } 
    va_end(arg_list); 
} 

Vector<int> v(3, 1, 2, 3); 

यह बेहतर हल किया जा सकता है, क्योंकि सभी तत्व समान रूप से टाइप किए गए हैं।

template < typename Iter, uint C > 
Vector< T, C >::Vector(Iter begin, Iter end) 
{ 
    T *data = m_data; 
    while(begin != end) 
     *data++ = *begin++; 
} 

int values[] = { 1, 2, 3 }; 
Vector<int> v(values, values + 3); 
बेशक

, तो आप यकीन है कि वहाँ m_data में पर्याप्त जगह है बनाने के लिए किया है।

+0

यदि हमारे पास पहले से ही 'टेम्पलेट <टाइपनाम टी, यूंट सी>' है और हम पहले से ही उपयोगकर्ता को 'int मान []' सरणी घोषित कर रहे हैं, तो यह संरक्षक होने के लिए सुरक्षित (आकार-वार) नहीं हो सकता है 'वेक्टर < T, C > :: वेक्टर (टी (और कॉन्स) [सी]) '? किसी सरणी या गतिशील सरणी के स्लाइस की अनुमति देने के अलावा, क्या कोई कारण है कि हमें उन्हें सरणी पास करने की अनुमति नहीं देनी चाहिए? –

+0

@ क्रिस हाँ हम ऐसा कर सकते हैं। मैंने पाया कि मुझे इटरेटर रेंज के तरीके को दिखाने के लिए पसंद आया, क्योंकि यह "आधिकारिक" तरीका भी कंटेनर आदि द्वारा उपयोग किया जाता है। आप 'वेक्टर v (प्रारंभ (मान), अंत (मान)) भी कर सकते हैं;' उचित रूप से परिभाषित 'अंत' और 'स्टार्ट' फ़ंक्शंस (boost.range से) के साथ तत्वों को स्वयं गिनें –

0

std::tr1::array (जो आपके जैसा दिखता है) एक निर्माता को परिभाषित नहीं करता, और एक समग्र रूप में प्रारंभ किया जा सकता है (?)

std::tr1::array<int, 10> arr = {{ 1, 2, 3, 4, 5, 6 }}; 

इसके अलावा, आप Boost.Assignment पुस्तकालय की जाँच कर सकते हैं।

उदाहरण के लिए निर्माता हो सकता है

Vector<int, 4> vec(boost::assign::cref_list_of<4>(1)(3)(4)(7)); 
0

आप variadic उपयोग कर सकते हैं के साथ बनाया

template < typename T, uint C > 
template < typename Range > 
Vector< T, C >::Vector(const Range& r) 

और उदाहरणों, variadic चर तर्क के साथ टेम्पलेट का मतलब है। more

0

कंस्ट्रक्टर्स में चर तर्क के साथ समस्या है:

  • आप cdecl सम्मेलन बुला (या एक और एक है कि varargs संभाल कर सकते हैं)
  • आप नहीं कर सकते cdecl एक निर्माता के लिए (MSVS में) को परिभाषित
  • की जरूरत

तो "सही" कोड (एमएस) हो सकता है:

template < typename T, uint C > __cdecl Vector< T, C >::Vector(T, ...) 

लेकिन संकलक कहेंगे:

निर्माता/नाशक (एमएस C4166)

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