क्यों नहीं कंस्ट्रक्टर से टेम्पलेट पैरामीटर?


102

मेरा सवाल आज बहुत आसान है: क्लास कंस्ट्रक्टरों से कंपाइलर इंप्रेस टेम्पलेट पैरामीटर क्यों नहीं हो सकते, यह फंक्शन पैरामीटर्स से कितना हो सकता है? उदाहरण के लिए, निम्नलिखित कोड मान्य क्यों नहीं हो सकता है:

template<typename obj>
class Variable {
      obj data;
      public: Variable(obj d)
              {
                   data = d;
              }
};

int main()
{
    int num = 2;
    Variable var(num); //would be equivalent to Variable<int> var(num),
    return 0;          //but actually a compile error
}

जैसा कि मैं कहता हूं, मैं समझता हूं कि यह मान्य नहीं है, इसलिए मेरा सवाल यह है कि ऐसा क्यों नहीं है? क्या यह किसी भी प्रमुख वाक्यात्मक छेद बनाने की अनुमति देगा? क्या कोई ऐसा उदाहरण है जहां कोई इस कार्यक्षमता को नहीं चाहेगा (जहां एक प्रकार का इनफ़ॉर्मेशन मुद्दों का कारण होगा)? मैं सिर्फ कार्यों के लिए टेम्पलेट की अनुमति के पीछे के तर्क को समझने की कोशिश कर रहा हूं, फिर भी उपयुक्त रूप से निर्मित कक्षाओं के लिए नहीं।


मैं किसी को आमंत्रित करता हूं (मैं ऐसा करता हूं, अभी नहीं), ड्रेकर और पिटीस के जवाब (कम से कम) को अच्छे काउंटर-उदाहरणों के रूप में संकलित करने के लिए कि यह क्यों काम नहीं कर सकता है
jpinto3912

2
यह भी ध्यान दें कि इसके माध्यम से आसानी से काम किया जाता हैtemplate<class T> Variable<T> make_Variable(T&& p) {return Variable<T>(std::forward<T>(p));}
मूइंग डक

3
आप जो चाहें प्राप्त कर सकते हैं जैसे var = Variable <घोषणापत्र (n)> (n);
QuentinUK

18
सी ++ 17 यह अनुमति देगा! इस प्रस्ताव को स्वीकार कर लिया गया: open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0091r0.html
underscore_d

1
@underscore_d बहुत बढ़िया! समय के बारे में! यह मेरे लिए स्वाभाविक था कि जिस तरह से यह काम करना चाहिए, और जलन का स्रोत यह नहीं था।
आमोद

जवाबों:


46

मुझे लगता है कि यह मान्य नहीं है क्योंकि निर्माता हमेशा कक्षा के प्रवेश का एकमात्र बिंदु नहीं है (मैं कॉपी निर्माता और ऑपरेटर = के बारे में बात कर रहा हूं)। तो मान लीजिए कि आप अपनी कक्षा का इस तरह उपयोग कर रहे हैं:

MyClass m(string s);
MyClass *pm;
*pm = m;

मुझे यकीन नहीं है कि क्या पार्सर के लिए यह जानना स्पष्ट होगा कि MyClass pm कौन सा टेम्पलेट प्रकार है;

यकीन नहीं होता कि मैंने जो कहा वह समझ में आता है लेकिन कुछ टिप्पणी करने के लिए स्वतंत्र महसूस करें, यह एक दिलचस्प सवाल है।

सी ++ 17

यह स्वीकार किया जाता है कि सी ++ 17 में कंस्ट्रक्टर तर्कों से कटौती होगी।

उदाहरण:

std::pair p(2, 4.5);
std::tuple t(4, 3, 2.5);

स्वीकृत कागज


8
यह वास्तव में एक महान बिंदु है जिस पर मैंने कभी विचार नहीं किया। मुझे इस तथ्य के आसपास कोई रास्ता नहीं दिखता है कि सूचक को विशिष्ट होना होगा (यानी इसे MyClass <string> * pm) होना होगा। अगर ऐसा है, तो आप जो कुछ भी कर रहे हैं, वह सभी प्रकार के तात्कालिकता को निर्दिष्ट करने से खुद को बचा रहा है; अतिरिक्त काम के कुछ मात्र पात्र (और केवल यदि ऑब्जेक्ट स्टैक पर बनाया गया है, न कि ढेर, ऊपर दिए अनुसार)। मुझे हमेशा यह संदेह था कि कक्षा में प्रवेश करने से कीड़े का एक सिंटैक्टिक कैन खुल सकता है, और मुझे लगता है कि यह ऐसा हो सकता है।
जीआरबी

2
मैं यह नहीं देखता कि निर्माणकर्ताओं से टेम्प्लेट-पैरामीटर निष्कासन की अनुमति देना आपकी दूसरी पंक्ति की तरह, बिना कंस्ट्रक्टर के गैर-विशिष्ट घोषणाओं की अनुमति देने की आवश्यकता है । यानी, MyClass *pmयहां उसी कारण के लिए अमान्य होगा जो घोषित किए गए फ़ंक्शन template <typename T> void foo();को स्पष्ट विशेषज्ञता के बिना नहीं बुलाया जा सकता है।
काइल स्ट्रैंड

3
@KyleStrand हाँ, यह कहकर कि 'क्लास टेम्प्लेट की दलीलें उनके कंस्ट्रक्टरों से नहीं ली जा सकतीं, क्योंकि [उदाहरण जो किसी कंस्ट्रक्टर का उपयोग नहीं करता है] , यह उत्तर पूरी तरह से अप्रासंगिक है। मैं वास्तव में विश्वास नहीं कर सकता कि यह स्वीकार किया गया था, +29 तक पहुंच गया, किसी को चमकती समस्या को नोटिस करने के लिए 6 साल लग गए, और 7 साल तक एक भी डाउनवोट के बिना बैठ गया। क्या कोई और नहीं सोचता है कि वे पढ़ते हैं, या ...?
अंडरस्कोर_ड

1
@underscore_d मुझे पसंद है, जैसा कि यह वर्तमान में खड़ा है, यह उत्तर कहता है "इस प्रस्ताव के साथ कुछ समस्याएं हो सकती हैं, मुझे यकीन नहीं है कि अगर मैंने जो कहा है वह समझ में आता है (!), टिप्पणी करने के लिए स्वतंत्र महसूस करें! (!!);" ओह, वैसे यह बहुत ज्यादा ठीक है कि सी ++ 17 कैसे काम करेगा। "
काइल स्ट्रैंड

1
@KyleStrand आह हाँ, यह अभी तक एक और मुद्दा है, जिस पर मैंने गौर किया लेकिन अन्य सभी मौज-मस्ती का उल्लेख करना भूल गया। C ++ 17 के बारे में संपादन ओपी द्वारा नहीं किया गया था ... और IMO को अनुमोदित नहीं किया जाना चाहिए था, लेकिन एक नए उत्तर के रूप में पोस्ट किया गया था: यह पोस्ट के होने पर भी 'पोस्ट के परिवर्तन अर्थ' के रूप में निर्णायक होगा। शुरू करने के लिए गैर-अर्थहीन ... मैं संपादन से अवगत नहीं था-पूरी तरह से नए वर्गों में निष्पक्ष खेल था और निश्चित रूप से कम कठोर संपादन अस्वीकार कर दिए गए थे, लेकिन मुझे लगता है कि आपको समीक्षकों की दृष्टि से ड्रा का सौभाग्य मिला है।
अंडरस्कोर_ड

27

आप उन कारणों के बारे में नहीं पूछ सकते हैं जो अन्य लोगों ने संबोधित किए हैं, लेकिन आप ऐसा कर सकते हैं:

template<typename T>
class Variable {
    public: Variable(T d) {}
};
template<typename T>
Variable<T> make_variable(T instance) {
  return Variable<T>(instance);
}

जो सभी इरादों और उद्देश्यों के लिए वही चीज है जो आप मांगते हैं। यदि आपको एनकैप्सुलेशन पसंद है तो आप make_variable को static सदस्य फ़ंक्शन बना सकते हैं। जिसे लोग कंस्ट्रक्टर नाम देते हैं। तो न केवल यह वही करता है जो आप चाहते हैं, लेकिन यह लगभग वही है जो आप चाहते हैं: कंपाइलर (नामित) कंस्ट्रक्टर से टेम्पलेट पैरामीटर को हटा रहा है।

नायब: कोई भी उचित संकलक अस्थायी वस्तु को दूर कर देगा जब आप कुछ लिखेंगे

auto v = make_variable(instance);

6
यह इंगित करना चाहते हैं कि ऐसे मामले में कार्य स्थैतिक सदस्य बनाने के लिए यह विशेष रूप से उपयोगी नहीं है क्योंकि इसके लिए आपको किसी वर्ग को किसी भी तरह से कॉल करने के लिए टेम्पलेट तर्क निर्दिष्ट करना होगा, इसलिए इसे समर्पित करने का कोई मतलब नहीं होगा।
प्रेडेलनिक डे

3
और C ++ 11 में भी बेहतर आप ऐसा कर सकते हैं auto v = make_variable(instance)ताकि आपको वास्तव में टाइप करने की आवश्यकता न हो
Claudiu

1
हाँ, मेक फंक्शन को एक staticसदस्य के रूप में घोषित करने के विचार पर लोल ... इस बारे में एक दूसरे के लिए सोचें। वह एक तरफ: नि: शुल्क मेक फ़ंक्शंस वास्तव में समाधान थे , लेकिन यह बहुत अधिक अनावश्यक बॉयलरप्लेट है, कि जब आप इसे टाइप कर रहे हैं, तो आप बस यह जानते हैं कि आपको संकलक को उन सभी सूचनाओं तक पहुंच नहीं होनी चाहिए जो आप दोहरा रहे हैं। .. और शुक्र है कि सी + + 17 canonises कि।
अंडरस्कोर_ड

21

2016 के प्रबुद्ध युग में, हमारे बेल्ट के नीचे दो नए मानकों के साथ जब से यह सवाल पूछा गया था और कोने के चारों ओर एक नया था, यह जानने के लिए महत्वपूर्ण बात यह है कि C ++ 17 मानक का समर्थन करने वाले कंपाइलर आपके कोड को इस प्रकार संकलित करेंगे

C ++ 17 में वर्ग टेम्पलेट के लिए टेम्पलेट-तर्क कटौती

यहाँ (स्वीकार किए गए उत्तर के ओल्झास ज़ुमबेक द्वारा एक संपादन के सौजन्य से) मानक में प्रासंगिक परिवर्तनों का विवरण देने वाला कागज़ है।

अन्य उत्तरों से चिंताओं को संबोधित करना

वर्तमान टॉप-रेटेड उत्तर

यह उत्तर बताता है कि "प्रतिलिपि निर्माता और operator=" सही टेम्पलेट विशेषज्ञताओं को नहीं जान पाएंगे।

यह बकवास है, क्योंकि मानक कॉपी-कंस्ट्रक्टर और operator= केवल एक ज्ञात टेम्पलेट प्रकार के लिए मौजूद है :

template <typename T>
class MyClass {
    MyClass(const MyClass&) =default;
    ... etc...
};

// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm;   // WHAT IS THIS?
*pm = m;

यहाँ, के रूप में मैं टिप्पणी में बताया गया है, है कोई कारण नहीं के लिए MyClass *pmके साथ या अनुमान के नए रूप के बिना एक कानूनी घोषणा-पत्र होने के लिए: MyClass एक प्रकार की नहीं है (यह एक टेम्पलेट है), तो यह मतलब नहीं है की एक सूचक की घोषणा करने के टाइप करें MyClass। उदाहरण को ठीक करने का एक संभावित तरीका यहां दिया गया है:

MyClass m(string("blah blah blah"));
decltype(m) *pm;               // uses type inference!
*pm = m;

यहाँ, pmहै पहले से ही सही प्रकार की है, और इसलिए निष्कर्ष तुच्छ है। इसके अलावा, कॉपी-कंस्ट्रक्टर को कॉल करते समय गलती से मिक्स टाइप करना असंभव है :

MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));

यहाँ, pmकी प्रतिलिपि करने के लिए एक सूचक होगा m। यहाँ, MyClassका निर्माण किया जा रहा है , mजो कि प्रकार का है MyClass<string>(और कोई नहीं के प्रकार के MyClass)। इस प्रकार, उस बिंदु पर जहां pmप्रकार का अनुमान लगाया गया है, यह जानने के लिए पर्याप्त जानकारी है कि टेम्पलेट-प्रकार m, और इसलिए टेम्पलेट-प्रकार pm, है string

इसके अलावा, निम्नलिखित हमेशा एक संकलन त्रुटि उठाएगा :

MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;

इसका कारण यह है कि कॉपी कंस्ट्रक्टर की घोषणा को समाप्त नहीं किया गया है:

MyClass(const MyClass&);

यहां, कॉपी-कंस्ट्रक्टर तर्क के टेम्प्लेट-प्रकार समग्र रूप से वर्ग के टेम्पलेट-प्रकार से मेल खाते हैं ; यानी, जब MyClass<string>instantiated है, MyClass<string>::MyClass(const MyClass<string>&);इसके साथ instantiated है, और जब MyClass<int>instantiated है, MyClass<int>::MyClass(const MyClass<int>&);instantiated है। जब तक यह स्पष्ट रूप से निर्दिष्ट नहीं किया जाता है या एक अस्थायी निर्माणकर्ता घोषित किया जाता है, तब तक संकलक के लिए कोई कारण नहीं MyClass<int>::MyClass(const MyClass<string>&);होता है, जो स्पष्ट रूप से अनुचित होगा।

इसका जवाब Cătălin Pitit ने दिया है

Piti P एक उदाहरण प्रस्तुत करता है Variable<int>और Variable<double>फिर कहता है:

मेरे पास दो अलग-अलग प्रकारों (Variable and Variable) के लिए कोड में एक ही प्रकार का नाम (Variable) है। मेरे व्यक्तिपरक दृष्टिकोण से, यह कोड की पठनीयता को काफी प्रभावित करता है।

जैसा कि पिछले उदाहरण में उल्लेख किया गया है, Variableअपने आप में एक प्रकार का नाम नहीं है, भले ही नई विशेषता यह एक वाक्यात्मक रूप से दिखती है।

Piti तो पूछता है कि अगर कोई कंस्ट्रक्टर नहीं दिया जाता है तो क्या होगा जो उचित अनुमान लगाने की अनुमति देगा। इसका उत्तर यह है कि किसी भी प्रकार के इंजेक्शन की अनुमति नहीं है, क्योंकि निर्माणकर्ता द्वारा कॉल करने पर ट्रिगर चालू हो जाता है । बिना कंस्ट्रक्टर-कॉल के, कोई निष्कर्ष नहीं है

यह पूछने के लिए समान है कि यहाँ किस संस्करण fooको घटाया गया है:

template <typename T> foo();
foo();

उत्तर यह है कि यह कोड अवैध है, कारण बताया गया है।

MSalter का जवाब

यह है, जहां तक ​​मैं बता सकता हूं, प्रस्तावित सुविधा के बारे में एक वैध चिंता लाने का एकमात्र उत्तर है।

उदाहरण है:

Variable var(num);  // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?

अहम सवाल यह है कि क्या कंपाइलर यहां -टाइप कंस्ट्रक्टर का चयन करता है या कॉपी कंस्ट्रक्टर का?

कोड को आज़माकर, हम देख सकते हैं कि कॉपी कंस्ट्रक्टर का चयन किया गया है। उदाहरण पर विस्तार करने के लिए :

Variable var(num);          // infering ctor
Variable var2(var);         // copy ctor
Variable var3(move(var));   // move ctor
// Variable var4(Variable(num));     // compiler error

मुझे यकीन नहीं है कि प्रस्ताव और मानक का नया संस्करण यह कैसे निर्दिष्ट करता है; यह "डिडक्शन गाइड्स" द्वारा निर्धारित किया गया प्रतीत होता है, जो एक नया मानक है जो मुझे अभी तक समझ में नहीं आया है।

मुझे यह भी सुनिश्चित नहीं है कि var4कटौती अवैध क्यों है; जी ++ से संकलक त्रुटि इंगित करती है कि कथन को फ़ंक्शन की घोषणा के रूप में पार्स किया जा रहा है।


क्या शानदार, विस्तृत जवाब! var4केवल "सबसे अधिक डरावनी पार्स" (टेम्पलेट arg कटौती से संबंधित नहीं) का मामला है। हम इसके लिए सिर्फ अतिरिक्त पेरेन्स का उपयोग करते थे, लेकिन इन दिनों मुझे लगता है कि ब्रेसिज़ का उपयोग करने के लिए बिना सोचे समझे निर्माण सामान्य सलाह है।
सुमुदु फर्नांडो

@SumuduFernando धन्यवाद! क्या आपका मतलब है कि Variable var4(Variable(num));एक फ़ंक्शन घोषणा के रूप में माना जाता है? यदि हां, तो Variable(num)एक मान्य पैरामीटर विनिर्देश क्यों है ?
काइल स्ट्रैंड

@SumuduFernando कोई बात नहीं, मुझे नहीं पता था कि यह मान्य था: coliru.stacked-crooked.com/a/98c36b8082660941
काइल स्ट्रैंड

11

अभी भी लापता है: यह निम्नलिखित कोड को काफी अस्पष्ट बनाता है:

int main()
{
    int num = 2;
    Variable var(num);  // If equivalent to Variable<int> var(num),
    Variable var2(var); //Variable<int> or Variable<Variable<int>> ?
}

एक और अच्छी बात। यह मानते हुए कि एक कॉपी कंस्ट्रक्टर मौजूद है जो वेरिएबल (Variable <obj> d) परिभाषित है, वहाँ किसी प्रकार की पूर्ववर्तीता स्थापित करनी होगी।
GRB

1
या, वैकल्पिक रूप से, कंपाइलर ने एक अपरिभाषित टेम्प्लेट पैरामीटर त्रुटि को फिर से फेंक दिया है, बहुत कुछ जैसा कि मैंने पिटीस के जवाब के संबंध में सुझाव दिया है। हालांकि, यदि आप उस मार्ग को लेते हैं, तो कई बार जहां समस्याएँ (त्रुटियां) हो सकती हैं, वह छोटी और छोटी हो रही है।
GRB

यह वास्तव में एक दिलचस्प बिंदु है, और (जैसा कि मैंने अपने उत्तर में नोट किया है) मुझे अभी तक यकीन नहीं है कि स्वीकृत सी ++ 17 प्रस्ताव यह कैसे हल करता है।
काइल स्ट्रैंड

9

यह मानते हुए कि संकलक आपके द्वारा पूछे गए समर्थन का समर्थन करता है। तब यह कोड मान्य है:

Variable v1( 10); // Variable<int>

// Some code here

Variable v2( 20.4); // Variable<double>

अब, मेरे पास दो अलग-अलग प्रकारों (Variable and Variable) के लिए कोड में एक ही प्रकार का नाम (Variable) है। मेरे व्यक्तिपरक दृष्टिकोण से, यह कोड की पठनीयता को काफी प्रभावित करता है। एक ही नामस्थान में दो भिन्न प्रकारों के लिए एक ही प्रकार का नाम होने से मुझे भ्रामक लगता है।

बाद में अपडेट: विचार करने के लिए एक और बात: आंशिक (या पूर्ण) टेम्पलेट विशेषज्ञता।

क्या होगा यदि मैं वैरिएबल को विशेषज्ञता देता हूं और आपको उम्मीद के मुताबिक कोई कंस्ट्रक्टर नहीं देता है?

तो मेरे पास होगा:

template<>
class Variable<int>
{
// Provide default constructor only.
};

फिर मेरे पास कोड है:

Variable v( 10);

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


1
इससे भी बदतर: क्या होगा यदि आपके पास केवल परिवर्तनीय <int> :: चर (फ्लोट) है? अब आपके पास Variable (1f) को घटाने के दो तरीके हैं और Variable (1) को कम करने का कोई तरीका नहीं है।
MSalters

यह एक अच्छा बिंदु है, लेकिन कास्टिंग द्वारा आसानी से पार किया जा सकता है: चर v1 ((डबल) 10)
jpinto3912

मैं मानता हूं कि कोड पठनीयता एक व्यक्तिपरक मुद्दा है, हालांकि, मैं खासतौर पर टेम्पलेट विशेषज्ञता पर जो कह रहा हूं, उसके साथ 100% सहमत हूं। समाधान शायद एक अपरिभाषित टेम्पलेट पैरामीटर त्रुटि देने के लिए होगा (एक बार कंपाइलर <int> विशेषज्ञता को देखता है और कोई वैध कंस्ट्रक्टर नहीं देखता है, तो यह कहना है कि इसका कोई मतलब नहीं है कि आप किस टेम्पलेट का उपयोग करना चाहते हैं और आपको स्पष्ट रूप से निर्दिष्ट करना होगा) लेकिन मैं मानता हूं कि यह एक सुंदर समाधान नहीं है। मैं इसे एक और प्रमुख जोड़-तोड़ छेद के रूप में जोड़ूंगा, जिससे निपटने की आवश्यकता होगी (लेकिन यदि कोई परिणाम स्वीकार करता है तो इसे हल किया जा सकता है)।
जीआरबी

4
@ jpinto3912 - आप बिंदु को याद कर रहे हैं। संकलक को किसी भी ctor चर <t> :: चर की जाँच करने के लिए सभी संभव चर <t> का तात्पर्य है: चर एक अस्पष्ट ctor प्रदान करता है। अस्पष्टता से छुटकारा पाना समस्या नहीं है - सरल तात्कालिक चर <दोहरा> यदि आप चाहते हैं तो अपने आप को। यह पहली जगह में उस अस्पष्टता को खोज रहा है जो इसे असंभव बनाता है।
एमएसलटर्स

6

C ++ 03 और C ++ 11 मानक कांस्ट्रेक्टर को दिए गए मापदंडों से टेम्पलेट तर्क कटौती की अनुमति नहीं देते हैं।

लेकिन "कंस्ट्रक्टरों के लिए टेम्पलेट पैरामीटर कटौती" के लिए एक प्रस्ताव है, इसलिए आपको वह मिल सकता है जो आप जल्द ही मांग रहे हैं। संपादित करें: वास्तव में, यह सुविधा C ++ 17 के लिए पुष्टि की गई है।

देखें: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3602.html और http://www.open-std.org/jtc1/sc22/wg21/docs/ कागजात / 2015 / p0091r0.html


सुविधा को C ++ 17 में जोड़ा गया है, लेकिन ऐसा नहीं है यदि "जल्द ही" 6 से 8 वर्ष की समय सीमा पर लागू होता है। ;)
चेत

2

बहुत सारी कक्षाएं निर्माता मापदंडों पर निर्भर नहीं करती हैं। कुछ वर्ग ही ऐसे हैं, जिनके पास केवल एक कंस्ट्रक्टर है, और इस कंस्ट्रक्टर के प्रकार के आधार पर पैरामीटर बनाते हैं।

यदि आपको वास्तव में टेम्प्लेट की आवश्यकता है, तो एक सहायक फ़ंक्शन का उपयोग करें:

template<typename obj>
class Variable 
{
      obj data;
public: 
      Variable(obj d)
      : data(d)
      { }
};

template<typename obj>
inline Variable<obj> makeVariable(const obj& d)
{
    return Variable<obj>(d);
}

1
बेशक यह कार्यक्षमता केवल कुछ वर्गों के लिए उपयोगी साबित होगी, लेकिन फ़ंक्शन के निष्कर्ष के लिए भी यही कहा जा सकता है। सभी अस्थायी कार्य अपने मापदंडों को तर्क सूची से नहीं लेते हैं, फिर भी हम उन कार्यों के लिए अनुमति देते हैं जो करते हैं।
जीआरबी

1

प्रकारों की कटौती वर्तमान C ++ में टेम्पलेट फ़ंक्शन तक सीमित है, लेकिन यह लंबे समय से महसूस किया गया है कि अन्य संदर्भों में टाइप कटौती बहुत उपयोगी होगी। इसलिए C ++ 0x का auto

जबकि वास्तव में क्या आप सुझाव है कि C ++ 0x में संभव नहीं होगा, तो निम्न से पता चलता है कि आप बहुत करीब प्राप्त कर सकते हैं:

template <class X>
Variable<typename std::remove_reference<X>::type> MakeVariable(X&& x)
{
    // remove reference required for the case that x is an lvalue
    return Variable<typename std::remove_reference<X>::type>(std::forward(x));
}

void test()
{
    auto v = MakeVariable(2); // v is of type Variable<int>
}

0

आप सही हैं कि कंपाइलर आसानी से अनुमान लगा सकता है, लेकिन यह मानक या C ++ 0x में नहीं है, जहां तक ​​मुझे पता है कि आपको कम से कम 10 साल इंतजार करना होगा (कंपाइलर प्रदाता इस सुविधा को जोड़ने से पहले आईएसओ मानक दर के आसपास निर्धारित)


आगामी मानक के साथ यह सही नहीं है कि एक ऑटो कीवर्ड पेश किया जाएगा। इस धागे में जेम्स हॉपकिंस के पद पर एक नज़र डालें। stackoverflow.com/questions/984394/… । वह दिखाता है कि यह C ++ 0x में कैसे संभव होगा।
ओवन्स

1
बस अपने आप को सही करने के लिए, ऑटो कीवर्ड भी वर्तमान मानक में मौजूद है, लेकिन अलग उद्देश्य के लिए।
ओवन्स

ऐसा लगता है कि यह (इस उत्तर के समय से) 8 साल हो जाएगा ... इसलिए 10 साल एक बुरा अनुमान नहीं था, भले ही मतलब समय में दो मानक रहे हों!
काइल स्ट्रैंड

-1

आइए समस्या को एक वर्ग के संदर्भ में देखें।

सबसे पहले, वेक्टर का एक बहुत ही सामान्य उपयोग उस निर्माता का उपयोग करना है जो कोई पैरामीटर नहीं लेता है:

vector <int> v;

इस मामले में, स्पष्ट रूप से कोई भी निष्कर्ष नहीं निकाला जा सकता है।

एक दूसरा आम उपयोग एक पूर्व-आकार वेक्टर बनाने के लिए है:

vector <string> v(100);

यहाँ, यदि प्रयोग किया जाता है:

vector v(100);

हमें चींटियों का एक सदिश मिलता है, तार नहीं, और संभवतः इसका आकार नहीं है!

अंतिम रूप से, उन कंस्ट्रक्टरों पर विचार करें जो कई पैरामीटर लेते हैं - "अनुमान" के साथ:

vector v( 100, foobar() );      // foobar is some class

किस पैरामीटर का उपयोग अनुमान के लिए किया जाना चाहिए? हमें संकलक को यह बताने का कोई तरीका चाहिए कि यह दूसरा होना चाहिए।

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


3
मुझे लगता है कि आप इस विचार को गलत समझ रहे हैं। कंस्ट्रक्टर्स के लिए टाइप इंट्रैक्शन केवल तब होगा जब टेम्पलेट टाइप कंस्ट्रक्टर का हिस्सा हो। मान लें कि वेक्टर में टेम्प्लेट की परिभाषा टेम्प्लेट है <टाइपनेम टी>। आपके उदाहरण में कोई समस्या नहीं है क्योंकि वेक्टर के निर्माता को वेक्टर (int आकार) के रूप में परिभाषित किया जाएगा, न कि वेक्टर (T आकार) में। केवल सदिश (टी आकार) के मामले में कोई निष्कर्ष निकलेगा; पहले उदाहरण में, कंपाइलर यह कहते हुए एक त्रुटि देगा कि टी अपरिभाषित है। अनिवार्य रूप से कैसे कार्य टेम्पलेट निष्कर्ष काम करता है के समान है।
GRB

तो यह केवल उन कंस्ट्रक्टरों के लिए होगा जिनके पास एक एकल पैरामीटर है और जहां वह पैरामीटर टेम्पलेट पैरामीटर प्रकार है? यह एक छोटा सा उदाहरण है।

यह जरूरी नहीं कि एक ही पैरामीटर हो। उदाहरण के लिए, कोई भी वेक्टर का वेक्टर निर्माण कर सकता है (int size, T FirstElement)। यदि किसी टेम्प्लेट में कई पैरामीटर होते हैं (टेम्पलेट <टाइपनेम टी, टाइपनेम नाम>), तो होल्डर होल्डर होल्डर (टी फर्स्टऑबजेक्ट, यू सेकंडऑब्जेक्ट) हो सकता है। यदि किसी टेम्प्लेट में कई पैरामीटर हैं, लेकिन कंस्ट्रक्टर केवल उनमें से एक लेता है, जैसे होल्डर (यू सेकंडऑबजेक्ट), तो टी को हमेशा स्पष्ट रूप से कहा जाना होगा। नियमों का उद्देश्य संभव के रूप में कार्य टेम्पलेट निष्कर्ष के समान होगा।
GRB

-2

Ctor को टेम्प्लेट बनाने से Variable का केवल एक ही रूप हो सकता है, लेकिन विभिन्न ctor :

class Variable {
      obj data; // let the compiler guess
      public:
      template<typename obj>
      Variable(obj d)
       {
           data = d;
       }
};

int main()
{
    int num = 2;
    Variable var(num);  // Variable::data int?

    float num2 = 2.0f;
    Variable var2(num2);  // Variable::data float?
    return 0;         
}

देख? हमारे पास कई चर :: डेटा सदस्य नहीं हो सकते।


यह किसी भी परिदृश्य के तहत समझ में नहीं आएगा। obj के संदर्भ में obj डेटा अपरिभाषित है क्योंकि वह वर्ग अब टेम्पलेट नहीं है। ऐसा कोड किसी भी तरह से अमान्य होगा।
जीआरबी

मुझे आपके द्वारा वर्णित कंपाइलर व्यवहार चाहिए था, इसलिए मैं उस प्रतिबंध (मेरे मामले में) को बायपास करने का एक तरीका खोजता हूं, जो आपको दिलचस्प, स्टैकओवरफ्लो.com
निक डंडौलकिस

-2

इस बारे में अधिक जानकारी के लिए C ++ टेम्पलेट तर्क कटौती देखें ।


4
मैंने इस लेख को पहले पढ़ा था और यह इस बारे में ज्यादा बात नहीं करता था कि मैं क्या कह रहा हूं। जब भी लेखक कक्षाओं के संबंध में तर्क कटौती के बारे में बात करता है, जब वह कहता है कि यह लेख के शीर्ष पर नहीं किया जा सकता है;) - यदि आप उन अनुभागों को इंगित कर सकते हैं जो आपको लगता है कि प्रासंगिक हैं, हालांकि मैं ' d वास्तव में सराहना करते हैं।
जीआरबी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.