2010-03-15 20 views
173

डिफ़ॉल्ट टेम्पलेट तर्क केवल क्लास टेम्पलेट्स पर क्यों अनुमत हैं? सदस्य फ़ंक्शन टेम्पलेट में हम डिफ़ॉल्ट प्रकार को परिभाषित क्यों नहीं कर सकते? उदाहरण के लिए:फ़ंक्शन टेम्पलेट्स के लिए डिफ़ॉल्ट टेम्पलेट तर्क

struct mycclass { 
    template<class T=int> 
    void mymember(T* vec) { 
    // ... 
    } 
}; 

इसके बजाय, सी ++ बल देता है कि डिफ़ॉल्ट टेम्पलेट तर्क केवल क्लास टेम्पलेट पर ही अनुमति दी जाती है।

+8

+1 यह वास्तव में एक मुश्किल सवाल है। – AraK

+1

पहले तीन पोस्ट किए गए उत्तरों के लिए, इस उदाहरण पर विचार करें: 'संरचना एस {टेम्पलेट <कक्षा आर = int> आर get_me_R() {\t वापसी आर(); }}; 'टेम्पलेट पैरामीटर को संदर्भ से नहीं लिया जा सकता है। – AraK

+3

अच्छा सवाल। 3 लोगों ने पहले ही यह कहने का उत्तर दिया है कि "यह समझ में नहीं आता", और वे सभी सामान्य रूप से गलत हैं। फंक्शन टेम्पलेट पैरामीटर * कॉल * पैरामीटर कॉल पैरामीटर से हमेशा कटौती योग्य नहीं होते हैं। उदाहरण के लिए, अगर उन्हें अनुमति दी गई तो मैं 'टेम्पलेट int और increment (int & i) {i + = N; वापसी मैं; } ', और फिर 'वृद्धि (i);' या 'वृद्धि <2> (i);'। जैसा कि है, मुझे 'वृद्धि <1> (i); 'लिखना है। –

उत्तर

138

डिफ़ॉल्ट टेम्पलेट तर्क देने के लिए यह समझ में आता है। उदाहरण के लिए आप एक प्रकार का फ़ंक्शन बना सकते हैं:

template<typename Iterator, 
     typename Comp = std::less< 
      typename std::iterator_traits<Iterator>::value_type> > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) { 
    ... 
} 

सी ++ 0x उन्हें सी ++ में पेश करता है। Bjarne Stroustrup द्वारा इस दोष रिपोर्ट देखें: Default Template Arguments for Function Templates और वह क्या

The prohibition of default template arguments for function templates is a misbegotten remnant of the time where freestanding functions were treated as second class citizens and required all template arguments to be deduced from the function arguments rather than specified.

The restriction seriously cramps programming style by unnecessarily making freestanding functions different from member functions, thus making it harder to write STL-style code.

+0

क्या उस जानकारी के साथ कुछ लिंक हैं? – Arman

+0

@ अरमान, दोष रिपोर्ट लिंक में सी ++ 0x और चर्चाओं के लिए कार्य ड्राफ्ट में किए गए परिवर्तन शामिल हैं। तर्क न तो निष्कासित और न ही स्पष्ट रूप से निर्दिष्ट डिफ़ॉल्ट तर्क से प्राप्त किए जाते हैं। GCC4.4 C++ 0x मोड में फ़ंक्शन टेम्पलेट्स के लिए डिफ़ॉल्ट तर्क का समर्थन करता है। –

+4

प्रश्न या उत्तर के साथ कुछ भी करने के लिए नहीं, लेकिन हर्ब सटर ने पिछले शनिवार की बैठक के बाद अपरिवर्तनीय मानक सी ++ 11 कहा। मैंने इसे आज पढ़ा और साझा करना पसंद किया :) http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ –

33

सी ++ टेम्पलेट्स के शब्दों में कहते हैं: पूरी गाइड (पेज 207):

When templates were originally added to the C++ language, explicit function template arguments were not a valid construct. Function template arguments always had to be deducible from the call expression. As a result, there seemed to be no compelling reason to allow default function template arguments because the default would always be overridden by the deduced value.

+0

सरल और संक्षिप्त :) – InQusitive

16

अब तक, सब के proffered उदाहरण फ़ंक्शन टेम्पलेट्स के लिए डिफ़ॉल्ट टेम्पलेट पैरामीटर ओवरलोड के साथ किया जा सकता है।

अरक:

struct S { 
    template <class R = int> R get_me_R() { return R(); } 
}; 

हो सकता है:

struct S { 
    template <class R> R get_me_R() { return R(); } 
    int get_me_R() { return int(); } 
}; 

मेरा अपना:

template <int N = 1> int &increment(int &i) { i += N; return i; } 

हो सकता है:

template <int N> int &increment(int &i) { i += N; return i; } 
int &increment(int &i) { return increment<1>(i); } 

litb:

template<typename Iterator, typename Comp = std::less<Iterator> > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) 

हो सकता है:

template<typename Iterator> 
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>()) 

template<typename Iterator, typename Comp > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) 

Stroustrup:

template <class T, class U = double> 
void f(T t = 0, U u = 0); 

हो सकता है:

template <typename S, typename T> void f(S s = 0, T t = 0); 
template <typename S> void f(S s = 0, double t = 0); 

कौन सा मैं निम्नलिखित कोड के साथ साबित कर दिया:

#include <iostream> 
#include <string> 
#include <sstream> 
#include <ctype.h> 

template <typename T> T prettify(T t) { return t; } 
std::string prettify(char c) { 
    std::stringstream ss; 
    if (isprint((unsigned char)c)) { 
     ss << "'" << c << "'"; 
    } else { 
     ss << (int)c; 
    } 
    return ss.str(); 
} 

template <typename S, typename T> void g(S s, T t){ 
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name() 
     << ">(" << s << "," << prettify(t) << ")\n"; 
} 


template <typename S, typename T> void f(S s = 0, T t = 0){ 
    g<S,T>(s,t); 
} 

template <typename S> void f(S s = 0, double t = 0) { 
    g<S,double>(s, t); 
} 

int main() { 
     f(1, 'c');   // f<int,char>(1,'c') 
     f(1);    // f<int,double>(1,0) 
//  f();    // error: T cannot be deduced 
     f<int>();   // f<int,double>(0,0) 
     f<int,char>();  // f<int,char>(0,0) 
} 

मुद्रित आउटपुट प्रत्येक कॉल के लिए टिप्पणियों से मेल खाता है, और टिप्पणी-आउट कॉल अपेक्षित रूप से संकलित करने में विफल रहता है।

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

लें कि आप निम्न समारोह करना चाहते हैं देता है:

+0

@ स्टेव: तो अंडे चिकन से तेजी से चल रहा था? :) दिलचस्प। धन्यवाद। – Arman

+1

शायद उन चीजों में से एक। सी ++ मानकीकरण प्रक्रिया भाग में धीमी गति से चलती है ताकि लोगों को यह समझने का समय हो कि परिवर्तन में मानक या कहीं और कठिनाई होती है। जब वे विरोधाभास या अस्पष्टता को देखते हैं, तो ड्राफ्ट मानक को लागू करने वाले लोगों द्वारा उम्मीदवारों को उम्मीदवारों द्वारा पकड़ा जाता है। उन चीज़ों को अनुमति देने के अवसर जिनकी अनुमति पहले नहीं थी, उन लोगों पर भरोसा करें जो कोड लिखना चाहते हैं, यह देखते हुए कि अब उन्हें अवैध नहीं होना चाहिए ... –

+2

आपके लिए एक और: 'टेम्पलेट <टाइपनाम टी = शून्य> int कुछ फ़ंक्शन() ; '। यहां टेम्पलेट पैरामीटर का कभी भी उपयोग नहीं किया जाता है, और वास्तव में फ़ंक्शन को कभी नहीं कहा जाता है; एकमात्र जगह जिसे इसे संदर्भित किया जाता है वह 'decltype' या 'sizeof' में है। नाम जानबूझकर किसी अन्य फ़ंक्शन के नाम से मेल खाता है लेकिन तथ्य यह है कि यह एक टेम्पलेट है, यदि यह मौजूद है तो संकलक मुफ्त फ़ंक्शन को प्राथमिकता देगा। दोनों को डिफ़ॉल्ट व्यवहार प्रदान करने के लिए SFINAE में उपयोग किया जाता है जहां फ़ंक्शन परिभाषा गुम होती है। – Tom

1

मैं क्या उपयोग अगले चाल है

template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array) 
{ 
    E one(1); 
    array.add(one); 
} 

आप अनुमति नहीं दी जाएगी, लेकिन मैं अगले तरीके से करना:

template <typename T> 
struct MyArray_t { 
void add(T i) 
{ 
    // ... 
} 
}; 

template <typename E, typename ARR_E = MyArray_t<E> > 
class worker { 
public: 
    /*static - as you wish */ ARR_E* parr_; 
    void doStuff(); /* do not make this one static also, MSVC complains */ 
}; 

template <typename E, typename ARR_E> 
void worker<E, ARR_E>::doStuff() 
{ 
    E one(1); 
    parr_->add(one); 
} 

तो इस तरह आप इसका उपयोग इस प्रकार कर सकते हैं:

MyArray_t<int> my_array; 
worker<int> w; 
w.parr_ = &arr; 
w.doStuff(); 

जैसा कि हम स्पष्ट रूप से दूसरे पैरामीटर को सेट करने की आवश्यकता नहीं देख सकते हैं। शायद यह किसी के लिए उपयोगी होगा।

+0

यह निश्चित रूप से एक उत्तर नहीं है। – Puppy

+0

@deadmg - क्या आप समझा सकते हैं क्यों? हम सभी सी ++ टेम्पलेट गुरु नहीं हैं। धन्यवाद। – Kev

+0

यह एक कामकाज है जो बहुत साफ है लेकिन इसमें उन सभी मामलों को शामिल नहीं किया जाएगा जिन्हें आप चाहें। उदाहरण के लिए आप इसे कन्स्ट्रक्टर पर कैसे लागू करेंगे? –

4

Windows पर, दृश्य स्टूडियो के सभी संस्करणों के साथ आप एक चेतावनी को यह त्रुटि (C4519) में परिवर्तित या तो की तरह उसे निष्क्रिय कर सकते हैं:

#ifdef _MSC_VER 
#pragma warning(1 : 4519) // convert error C4519 to warning 
// #pragma warning(disable : 4519) // disable error C4519 
#endif 

अधिक जानकारी के here देखें।

+1

ध्यान दें कि, जबकि यह "डिफ़ॉल्ट टेम्पलेट तर्क केवल क्लास टेम्पलेट पर अनुमति है" अक्षम करता है, यह वास्तव में टेम्पलेट तत्काल प्रक्रिया * उपयोग * प्रदान किए गए मान को नहीं बनाता है। इसके लिए वीएस2013 (या कोई अन्य कंपाइलर है जो सी ++ 11 दोष 226 "फ़ंक्शन टेम्पलेट्स के लिए डिफ़ॉल्ट टेम्पलेट तर्क" पूरा कर चुका है) – puetzk

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