वेरिएडिक टेम्प्लेट के संदर्भ में "..." टोकन के नियम क्या हैं?


98

C ++ 11 में इस तरह के वैरेडिक टेम्प्लेट हैं:

template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args )
{
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}

इसके बारे में कुछ जिज्ञासाएँ हैं: अभिव्यक्ति std::forward<Args>(args)...दोनों का उपयोग करती है Argsऔर argsकेवल एक ...टोकन। इसके अलावा std::forwardकेवल एक टेम्पलेट पैरामीटर और एक तर्क लेने वाला एक नॉन-वैरेडिक टेम्प्लेट फ़ंक्शन है। उस (मोटे तौर पर) के लिए वाक्यविन्यास नियम क्या हैं? इसे कैसे सामान्यीकृत किया जा सकता है?

इसके अलावा: कार्य कार्यान्वयन में दीर्घवृत्त ( ...) ब्याज की अभिव्यक्ति के अंत में है। क्या कोई कारण है कि टेम्पलेट तर्क सूची और पैरामीटर सूची में दीर्घवृत्त मध्य में है?


2
दूसरे भाग पर संक्षेप में: जब एक टेम्पलेट पैरामीटर पैक या फ़ंक्शन पैरामीटर पैक को "घोषित" किया जाता है, ...तो पहचानकर्ता को पेश किए जाने से पहले आता है। या तो या दोनों प्रकार के पैक का उपयोग करते समय, ...अभिव्यक्ति पैटर्न के विस्तार के बाद आता है।
aschepler

जवाबों:


99

वैरेडिक टेम्प्लेट के संदर्भ में, इलिप्सिस ...का उपयोग टेम्प्लेट पैरामीटर पैक को अनपैक करने के लिए किया जाता है यदि यह किसी अभिव्यक्ति के दाईं ओर दिखाई देता है ( एक पल के लिए इस अभिव्यक्ति पैटर्न को कॉल करें )। नियम यह है कि जो भी पैटर्न बाईं ओर है ...उसे दोहराया जाता है - अनपैक्ड पैटर्न (उन्हें अब अभिव्यक्ति कहते हैं) को अल्पविराम द्वारा अलग किया जाता है ,

इसे कुछ उदाहरणों से सबसे अच्छा समझा जा सकता है। मान लें कि आपके पास यह फ़ंक्शन टेम्प्लेट है:

template<typename ...T>
void f(T ... args) 
{
   g( args... );        //pattern = args
   h( x(args)... );     //pattern = x(args)
   m( y(args...) );     //pattern = args (as argument to y())
   n( z<T>(args)... );  //pattern = z<T>(args)
}

अब अगर मैं गुजर इस समारोह फोन Tके रूप में {int, char, short}, तो समारोह कॉल में से प्रत्येक के रूप में विस्तारित किया जाता है:

g( arg0, arg1, arg2 );           
h( x(arg0), x(arg1), x(arg2) );
m( y(arg0, arg1, arg2) );
n( z<int>(arg0), z<char>(arg1), z<short>(arg2) );

आपके द्वारा पोस्ट किए गए कोड में, फ़ंक्शन कॉल std::forwardद्वारा सचित्र चौथे पैटर्न का अनुसरण करता है n()

ऊपर x(args)...और y(args...)ऊपर का अंतर नोट करें !


आप ...सरणी को इनिशियलाइज़ करने के लिए निम्नानुसार भी उपयोग कर सकते हैं :

struct data_info
{
     boost::any  data;
     std::size_t type_size;
};

std::vector<data_info> v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)}

इसका विस्तार किया गया है:

std::vector<data_info> v 
{ 
   {arg0, sizeof(int)},
   {arg1, sizeof(char)},
   {arg2, sizeof(short)}
};

मैंने अभी महसूस किया कि एक पैटर्न भी शामिल हो सकता है जैसे कि एक्सेस स्पेसियर, जैसे publicकि निम्नलिखित उदाहरण में दिखाया गया है:

template<typename ... Mixins>
struct mixture : public Mixins ...  //pattern = public Mixins
{
    //code
};

इस उदाहरण में, पैटर्न का विस्तार इस प्रकार है:

struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN  

अर्थात्, सभी आधार वर्गों से सार्वजनिक रूप से mixtureप्राप्त होता है ।

उम्मीद है की वो मदद करदे।


1
मेल खाने वाले अभिव्यक्ति के बारे में; यह सबसे बड़ा संभव अभिव्यक्ति होना चाहिए, यह नहीं होना चाहिए? उदाहरण के लिए x+args...विस्तार किया जाना चाहिए x+arg0,x+arg1,x+arg2, नहीं x+arg0,arg1,arg2
बिटमैस्क

तो ...पैटर्न में हर विस्तार योग्य इकाई पर लागू होता है।
ऑर्बिट

@bitmask: हाँ। x+args...विस्तार करना चाहिए x+arg0,x+arg1,x+arg2, नहीं x+arg0,arg1,arg2
नवाज

1
@ Jarod42: C ++ 17 जारी होने के बाद मैं इस उत्तर को अपडेट करूंगा।
नवाज

3
@ सिंथ: sizeof...(T)वहाँ की जरूरत नहीं है। आप बस लिख सकते हैं:int a[] = { ___ };
नवाज़

48

GoingNative 2012 में आंद्रेई अलेक्जेंड्रेस्कु द्वारा "वेरिएडिक टेम्प्लेट्स फनडिक हैं " इस बात को निम्नलिखित से लिया गया है । मैं इसे वेरिएडिक टेम्प्लेट पर एक अच्छे परिचय के लिए सुझा सकता हूं।


एक चर पैक के साथ दो चीजें हो सकती हैं। sizeof...(vs)तत्वों की संख्या प्राप्त करने और इसका विस्तार करने के लिए आवेदन करना संभव है।

विस्तार के नियम

Use            Expansion

Ts...          T1, ..., Tn
Ts&&...        T1&&, ..., Tn&&
x<Ts,Y>::z...  x<T1,Y>::z, ..., x<Tn,Y>::z
x<Ts&,Us>...   x<T1&,U1>, ..., x<Tn&,Un>
func(5,vs)...  func(5,v1), ..., func(5,vn)

विस्तार आगे की ओर बढ़ता है। लॉक-स्टेप में दो सूचियों का विस्तार करते समय, उनका आकार समान होना चाहिए।

और ज्यादा उदाहरण:

gun(A<Ts...>::hun(vs)...);

Tsटेम्पलेट तर्क सूची में सभी का विस्तार करता है Aऔर फिर फ़ंक्शन hunको सभी के साथ विस्तारित किया जाता है vs

gun(A<Ts...>::hun(vs...));

Tsटेम्पलेट तर्क सूची में सभी का विस्तार करता है Aऔर सभी vsके लिए फ़ंक्शन तर्क के रूप में hun

gun(A<Ts>::hun(vs)...);

फ़ंक्शन hunको लॉक-स्टेप में Tsऔर उसके साथ विस्तारित करता है vs

ध्यान दें:

Tsएक प्रकार नहीं है और vsएक मूल्य नहीं है! वे प्रकार / मूल्यों की सूची के लिए उपनाम हैं। या तो सूची संभावित रूप से खाली हो सकती है। दोनों केवल विशिष्ट कार्यों का पालन करते हैं। तो निम्नलिखित संभव नहीं है:

typedef Ts MyList;  // error!
Ts var;             // error!
auto copy = vs;     // error!

विस्तार लोकी

तर्क वितर्क

template <typename... Ts>
void fun(Ts... vs)

प्रारंभिक सूची

any a[] = { vs... };

आधार निर्दिष्ट करनेवाला

template <typename... Ts>
struct C : Ts... {};
template <typename... Ts>
struct D : Box<Ts>... { /**/ };

सदस्य आरंभीक सूचियाँ

// Inside struct D
template <typename... Us>
D(Us... vs) : Box<Ts>(vs)... {}

अस्थायी तर्क सूची

std::map<Ts...> m;

केवल तभी संकलित करेंगे यदि तर्कों के लिए एक संभावित मैच हो।

सूची पर कब्जा

template <class... Ts> void fun(Ts... vs) {
    auto g = [&vs...] { return gun(vs...); }
    g();
}

सूचियाँ संलग्न करें

struct [[ Ts... ]] IAmFromTheFuture {};

यह विनिर्देश में है, लेकिन कोई विशेषता नहीं है जिसे एक प्रकार के रूप में व्यक्त किया जा सकता है, फिर भी।


अच्छा लगा। फ़ंक्शन तर्क को लोकी से छोड़ दिया जाता है, हालांकि: P
पोटाटोस्वाटर

@Potatoswatter साभार फ़ंक्शन तर्क सूची में विस्तार का उल्लेख नहीं किया गया था।
टाइप 1232

@ typ1232 संपादन के लिए क्षमा करें, लेकिन मुझे लगा कि आपकी मूल पोस्ट साहित्यिक चोरी के बहुत करीब थी। Btw, मैंने भी देखा कि कुछ समय पहले बात - भयानक।
वाल्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.