टेम्पलेट मेटाप्रोग्रामिंग: Difference between revisions

From Vigyanwiki
(Created page with "{{Short description|Metaprogramming technique}} {{More footnotes needed|date=June 2010}} {{Programming paradigms}} टेम्पलेट मेटाप्रोग्...")
 
No edit summary
Line 3: Line 3:
{{Programming paradigms}}
{{Programming paradigms}}


टेम्पलेट [[मेटाप्रोग्रामिंग]] (टीएमपी) एक मेटाप्रोग्रामिंग तकनीक है जिसमें एक [[ संकलक ]] द्वारा अस्थायी स्रोत कोड उत्पन्न करने के लिए [[ सामान्य प्रोग्रामिंग ]] का उपयोग किया जाता है, जिसे कंपाइलर द्वारा शेष स्रोत कोड के साथ विलय कर दिया जाता है और फिर संकलित किया जाता है। इन टेम्प्लेट के आउटपुट में [[ संकलन समय ]] | कंपाइल-टाइम कॉन्स्टेंट (प्रोग्रामिंग), [[डेटा संरचना]] और कम्पलीट [[ समारोह (कंप्यूटर विज्ञान) ]] शामिल हो सकते हैं। टेम्प्लेट के उपयोग को [[ संकलन-समय फ़ंक्शन निष्पादन ]] | कंपाइल-टाइम पॉलीमोर्फिज्म के रूप में माना जा सकता है। इस तकनीक का उपयोग कई भाषाओं में किया जाता है, जिनमें से सबसे प्रसिद्ध [[सी ++]] है, लेकिन [[कर्ल प्रोग्रामिंग भाषा]], [[डी प्रोग्रामिंग भाषा]], [[निम (प्रोग्रामिंग भाषा)]], और [[एक्सएल प्रोग्रामिंग भाषा]] भी है।
नमूना [[मेटाप्रोग्रामिंग]] टीएमपी एक मापन और संख्यात्मक तकनीक है जिसमें एक [[ संकलक ]] द्वारा अस्थायी स्रोत पारण चिन्ह उत्पन्न करने के लिए [[ सामान्य प्रोग्रामिंग |सामान्य प्रोग्रामिंग]] का उपयोग किया जाता है, जिसे कंपाइलर द्वारा शेष स्रोत कोड के साथ विलय कर दिया जाता है और फिर संकलित किया जाता है। इन टेम्प्लेट के आउटपुट में [[ संकलन समय ]] | कंपाइल-टाइम कॉन्स्टेंट (प्रोग्रामिंग), [[डेटा संरचना]] और कम्पलीट [[ समारोह (कंप्यूटर विज्ञान) ]] शामिल हो सकते हैं। टेम्प्लेट के उपयोग को [[ संकलन-समय फ़ंक्शन निष्पादन ]] | कंपाइल-टाइम पॉलीमोर्फिज्म के रूप में माना जा सकता है। इस तकनीक का उपयोग कई भाषाओं में किया जाता है, जिनमें से सबसे प्रसिद्ध [[सी ++]] है, लेकिन [[कर्ल प्रोग्रामिंग भाषा]], [[डी प्रोग्रामिंग भाषा]], [[निम (प्रोग्रामिंग भाषा)]], और [[एक्सएल प्रोग्रामिंग भाषा]] भी है।


टेम्पलेट मेटाप्रोग्रामिंग, एक अर्थ में, गलती से खोजी गई थी।<ref name="Meyers2005">{{cite book|author=Scott Meyers|title=Effective C++: 55 Specific Ways to Improve Your Programs and Designs|url=https://books.google.com/books?id=Qx5oyB49poYC&q=%22Template+metaprogramming%22|date=12 May 2005|publisher=Pearson Education|isbn=978-0-13-270206-5}}</ref><ref>See [[wikibooks:C++ Programming/Templates/Template Meta-Programming#History of TMP|History of TMP]] on Wikibooks</ref>
टेम्पलेट मेटाप्रोग्रामिंग, एक अर्थ में, गलती से खोजी गई थी।<ref name="Meyers2005">{{cite book|author=Scott Meyers|title=Effective C++: 55 Specific Ways to Improve Your Programs and Designs|url=https://books.google.com/books?id=Qx5oyB49poYC&q=%22Template+metaprogramming%22|date=12 May 2005|publisher=Pearson Education|isbn=978-0-13-270206-5}}</ref><ref>See [[wikibooks:C++ Programming/Templates/Template Meta-Programming#History of TMP|History of TMP]] on Wikibooks</ref>

Revision as of 07:27, 28 May 2023

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

टेम्पलेट मेटाप्रोग्रामिंग, एक अर्थ में, गलती से खोजी गई थी।[1][2] कुछ अन्य भाषाएं इसी तरह का समर्थन करती हैं, यदि अधिक शक्तिशाली नहीं, संकलन-समय की सुविधाएं (जैसे लिस्प (प्रोग्रामिंग भाषा) मैक्रो (कंप्यूटर विज्ञान)#सिंटैक्टिक मैक्रोज़), लेकिन वे इस लेख के दायरे से बाहर हैं।

टेम्पलेट मेटाप्रोग्रामिंग के घटक

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

टेम्प्लेट मेटाप्रोग्रामिंग ट्यूरिंग-पूर्ण है, जिसका अर्थ है कि कंप्यूटर प्रोग्राम द्वारा अभिव्यक्त किसी भी संगणना की गणना, किसी न किसी रूप में, टेम्प्लेट मेटाप्रोग्राम द्वारा की जा सकती है।[3] टेम्प्लेट मैक्रो (कंप्यूटर साइंस) # प्रोग्रामिंग मैक्रोज़ से अलग हैं। एक मैक्रो कोड का एक टुकड़ा है जो संकलन समय पर निष्पादित होता है और या तो संकलित किए जाने वाले कोड का शाब्दिक हेरफेर करता है (जैसे C ++ मैक्रोज़) या संकलक द्वारा उत्पादित सार वाक्य रचना का पेड़ में हेरफेर करता है (जैसे जंग (प्रोग्रामिंग भाषा) या लिस्प (प्रोग्रामिंग) भाषा) मैक्रोज़)। शाब्दिक मैक्रोज़ हेरफेर की जा रही भाषा के सिंटैक्स से विशेष रूप से अधिक स्वतंत्र हैं, क्योंकि वे संकलन से ठीक पहले स्रोत कोड के इन-मेमोरी टेक्स्ट को बदलते हैं।

टेम्पलेट मेटाप्रोग्राम में कोई अपरिवर्तनीय वस्तु नहीं है - अर्थात, एक बार प्रारंभ होने के बाद कोई चर मूल्य नहीं बदल सकता है, इसलिए टेम्पलेट मेटाप्रोग्रामिंग को कार्यात्मक प्रोग्रामिंग के रूप में देखा जा सकता है। वास्तव में कई टेम्पलेट कार्यान्वयन प्रवाह नियंत्रण को केवल रिकर्सन (कंप्यूटर विज्ञान) के माध्यम से लागू करते हैं, जैसा कि नीचे दिए गए उदाहरण में देखा गया है।

टेम्प्लेट मेटाप्रोग्रामिंग का उपयोग

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

संकलन-समय वर्ग पीढ़ी

संकलन-समय पर वास्तव में प्रोग्रामिंग का क्या अर्थ है, इसे फैक्टोरियल फ़ंक्शन के उदाहरण के साथ चित्रित किया जा सकता है, जो गैर-टेम्प्लेट सी ++ में रिकर्सन का उपयोग करके निम्नानुसार लिखा जा सकता है:

unsigned factorial(unsigned n) {
	return n == 0 ? 1 : n * factorial(n - 1); 
}

// Usage examples:
// factorial(0) would yield 1;
// factorial(4) would yield 24.

शाब्दिक 0 और 4 के भाज्य मान को निर्धारित करने के लिए उपरोक्त कोड रन टाइम पर निष्पादित होगा। पुनरावर्तन के लिए अंतिम स्थिति प्रदान करने के लिए टेम्प्लेट मेटाप्रोग्रामिंग और टेम्प्लेट विशेषज्ञता का उपयोग करके, प्रोग्राम में उपयोग किए जाने वाले फैक्टोरियल - उपयोग नहीं किए गए किसी भी फैक्टोरियल को अनदेखा करते हुए - इस कोड द्वारा संकलन समय पर गणना की जा सकती है:

template <unsigned N>
struct factorial {
	static constexpr unsigned value = N * factorial<N - 1>::value;
};

template <>
struct factorial<0> {
	static constexpr unsigned value = 1;
};

// Usage examples:
// factorial<0>::value would yield 1;
// factorial<4>::value would yield 24.

उपरोक्त कोड संकलन समय पर शाब्दिक 0 और 4 के भाज्य मान की गणना करता है और परिणामों का उपयोग करता है जैसे कि वे सटीक स्थिरांक थे। इस तरह से टेम्प्लेट का उपयोग करने में सक्षम होने के लिए, कंपाइलर को संकलन समय पर अपने मापदंडों के मूल्य का पता होना चाहिए, जिसमें प्राकृतिक पूर्व शर्त है कि फैक्टोरियल <X>::मान का उपयोग केवल तभी किया जा सकता है जब X को संकलन समय पर जाना जाता है। दूसरे शब्दों में, X एक स्थिर शाब्दिक या एक स्थिर अभिव्यक्ति होना चाहिए।

सी ++ 11 और सी ++ 20 में, कंपाइलर को कोड निष्पादित करने के लिए constexpr और कॉन्स्टेवल पेश किए गए थे। कॉन्स्टेक्सप्र और कॉन्स्टेवल का उपयोग करके, गैर-टेम्पलेटेड सिंटैक्स के साथ सामान्य पुनरावर्ती फैक्टोरियल परिभाषा का उपयोग किया जा सकता है।[4]


संकलन-समय कोड अनुकूलन

उपरोक्त फैक्टोरियल उदाहरण संकलन-समय कोड अनुकूलन का एक उदाहरण है जिसमें प्रोग्राम द्वारा उपयोग किए जाने वाले सभी फैक्टोरियल पूर्व-संकलित होते हैं और संकलन पर संख्यात्मक स्थिरांक के रूप में इंजेक्ट किए जाते हैं, रन-टाइम ओवरहेड और मेमोरी फ़ुटप्रिंट दोनों को बचाते हैं। हालाँकि, यह अपेक्षाकृत मामूली अनुकूलन है।

दूसरे के रूप में, अधिक महत्वपूर्ण, संकलन-समय लूप अनोलिंग का उदाहरण, टेम्पलेट मेटाप्रोग्रामिंग का उपयोग लंबाई-एन वेक्टर वर्ग बनाने के लिए किया जा सकता है (जहां एन को संकलन समय पर जाना जाता है)। अधिक पारंपरिक लंबाई-एन वेक्टर पर लाभ यह है कि लूप को अनियंत्रित किया जा सकता है, जिसके परिणामस्वरूप बहुत अनुकूलित कोड होता है। एक उदाहरण के रूप में, अतिरिक्त ऑपरेटर पर विचार करें। लंबाई-एन सदिश जोड़ को इस रूप में लिखा जा सकता है

template <int length>
Vector<length>& Vector<length>::operator+=(const Vector<length>& rhs) 
{
    for (int i = 0; i < length; ++i)
        value[i] += rhs.value[i];
    return *this;
}

जब संकलक ऊपर परिभाषित फ़ंक्शन टेम्पलेट को तुरंत चालू करता है, तो निम्न कोड उत्पन्न हो सकता है:[citation needed]

template <>
Vector<2>& Vector<2>::operator+=(const Vector<2>& rhs) 
{
    value[0] += rhs.value[0];
    value[1] += rhs.value[1];
    return *this;
}

कंपाइलर का ऑप्टिमाइज़र अनलॉक करने में सक्षम होना चाहिए for लूप क्योंकि टेम्पलेट पैरामीटर length संकलन समय पर स्थिर है।

हालाँकि, सावधानी बरतें और सावधानी बरतें क्योंकि इससे कोड ब्लोट हो सकता है क्योंकि प्रत्येक 'एन' (वेक्टर आकार) के लिए अलग-अलग अनियंत्रित कोड उत्पन्न होगा, जिसके साथ आप तुरंत चलते हैं।

स्थैतिक बहुरूपता

प्रकार बहुरूपता एक सामान्य मानक प्रोग्रामिंग सुविधा है जहां व्युत्पन्न वस्तुओं को उनके मूल वस्तु के उदाहरणों के रूप में उपयोग किया जा सकता है लेकिन जहां व्युत्पन्न वस्तुओं के तरीकों को लागू किया जाएगा, जैसा कि इस कोड में है

class Base
{
public:
    virtual void method() { std::cout << "Base"; }
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    virtual void method() { std::cout << "Derived"; }
};

int main()
{
    Base *pBase = new Derived;
    pBase->method(); //outputs "Derived"
    delete pBase;
    return 0;
}

जहां के सभी आह्वान virtual विधियाँ सर्वाधिक व्युत्पन्न वर्ग की होंगी। यह गतिशील रूप से बहुरूपी व्यवहार (आमतौर पर) vtable के निर्माण द्वारा प्राप्त किया जाता है। वर्चुअल विधियों के साथ कक्षाओं के लिए वर्चुअल लुक-अप टेबल, टेबल जो रन टाइम पर ट्रैवर्स किए जाते हैं ताकि आह्वान की जाने वाली विधि की पहचान हो सके। इस प्रकार, रन-टाइम बहुरूपता आवश्यक रूप से निष्पादन ओवरहेड (हालांकि आधुनिक आर्किटेक्चर पर ओवरहेड छोटा है) पर जोर देता है।

हालाँकि, कई मामलों में आवश्यक बहुरूपी व्यवहार अपरिवर्तनीय है और संकलन समय पर निर्धारित किया जा सकता है। फिर जिज्ञासु आवर्ती टेम्पलेट पैटर्न (CRTP) का उपयोग 'स्थैतिक बहुरूपता' को प्राप्त करने के लिए किया जा सकता है, जो प्रोग्रामिंग कोड में बहुरूपता की नकल है, लेकिन जिसे संकलन समय पर हल किया जाता है और इस प्रकार रन-टाइम वर्चुअल-टेबल लुकअप से दूर हो जाता है। उदाहरण के लिए:

template <class Derived>
struct base
{
    void interface()
    {
         // ...
         static_cast<Derived*>(this)->implementation();
         // ...
    }
};

struct derived : base<derived>
{
     void implementation()
     {
         // ...
     }
};

यहां बेस क्लास टेम्पलेट इस तथ्य का लाभ उठाएगा कि सदस्य फ़ंक्शन निकायों को उनकी घोषणा के बाद तक तत्काल नहीं किया जाता है, और यह व्युत्पन्न वर्ग के सदस्यों को अपने स्वयं के सदस्य कार्यों के उपयोग के माध्यम से उपयोग करेगा static_cast, इस प्रकार संकलन में बहुरूपी विशेषताओं के साथ एक वस्तु रचना उत्पन्न होती है। वास्तविक दुनिया के उपयोग के उदाहरण के रूप में, CRTP का उपयोग बूस्ट लाइब्रेरी इटरेटर लाइब्रेरी में किया जाता है।[5] एक अन्य समान उपयोग बार्टन-नैकमैन ट्रिक है, जिसे कभी-कभी प्रतिबंधित टेम्पलेट विस्तार के रूप में संदर्भित किया जाता है, जहां सामान्य कार्यक्षमता को एक आधार वर्ग में रखा जा सकता है जिसका उपयोग अनुबंध के रूप में नहीं बल्कि कोड अतिरेक को कम करते हुए अनुरूप व्यवहार को लागू करने के लिए एक आवश्यक घटक के रूप में किया जाता है।

स्टेटिक टेबल जनरेशन

स्थैतिक तालिकाओं का लाभ एक साधारण सरणी अनुक्रमण ऑपरेशन के साथ महंगी गणनाओं का प्रतिस्थापन है (उदाहरण के लिए, लुकअप तालिका देखें)। सी ++ में, संकलन समय पर स्थिर तालिका उत्पन्न करने के एक से अधिक तरीके मौजूद हैं। निम्न सूची रिकर्सिव स्ट्रक्चर्स और विविध टेम्पलेट्स का उपयोग करके एक बहुत ही सरल तालिका बनाने का एक उदाहरण दिखाती है। तालिका का आकार दस है। प्रत्येक मान सूचकांक का वर्ग है।

#include <iostream>
#include <array>

constexpr int TABLE_SIZE = 10;

/**
 * Variadic template for a recursive helper struct.
 */
template<int INDEX = 0, int ...D>
struct Helper : Helper<INDEX + 1, D..., INDEX * INDEX> { };

/**
 * Specialization of the template to end the recursion when the table size reaches TABLE_SIZE.
 */
template<int ...D>
struct Helper<TABLE_SIZE, D...> {
  static constexpr std::array<int, TABLE_SIZE> table = { D... };
};

constexpr std::array<int, TABLE_SIZE> table = Helper<>::table;

enum  {
  FOUR = table[2] // compile time use
};

int main() {
  for (int i=0; i < TABLE_SIZE; i++) {
    std::cout << table[i]  << std::endl; // run time use
  }
  std::cout << "FOUR: " << FOUR << std::endl;
}

इसके पीछे विचार यह है कि स्ट्रक्चर हेल्पर पुनरावर्ती रूप से एक संरचना से एक और टेम्पलेट तर्क (इस उदाहरण में INDEX * INDEX के रूप में गणना की गई) के साथ प्राप्त करता है जब तक कि टेम्पलेट की विशेषज्ञता 10 तत्वों के आकार पर पुनरावृत्ति समाप्त नहीं करती। विशेषज्ञता केवल चर तर्क सूची का उपयोग सरणी के तत्वों के रूप में करती है। संकलक निम्नलिखित के समान कोड का उत्पादन करेगा (क्लैंग से लिया गया जिसे -Xclang -ast-print -fsyntax-only कहा जाता है)।

template <int INDEX = 0, int ...D> struct Helper : Helper<INDEX + 1, D..., INDEX * INDEX> {
};
template<> struct Helper<0, <>> : Helper<0 + 1, 0 * 0> {
};
template<> struct Helper<1, <0>> : Helper<1 + 1, 0, 1 * 1> {
};
template<> struct Helper<2, <0, 1>> : Helper<2 + 1, 0, 1, 2 * 2> {
};
template<> struct Helper<3, <0, 1, 4>> : Helper<3 + 1, 0, 1, 4, 3 * 3> {
};
template<> struct Helper<4, <0, 1, 4, 9>> : Helper<4 + 1, 0, 1, 4, 9, 4 * 4> {
};
template<> struct Helper<5, <0, 1, 4, 9, 16>> : Helper<5 + 1, 0, 1, 4, 9, 16, 5 * 5> {
};
template<> struct Helper<6, <0, 1, 4, 9, 16, 25>> : Helper<6 + 1, 0, 1, 4, 9, 16, 25, 6 * 6> {
};
template<> struct Helper<7, <0, 1, 4, 9, 16, 25, 36>> : Helper<7 + 1, 0, 1, 4, 9, 16, 25, 36, 7 * 7> {
};
template<> struct Helper<8, <0, 1, 4, 9, 16, 25, 36, 49>> : Helper<8 + 1, 0, 1, 4, 9, 16, 25, 36, 49, 8 * 8> {
};
template<> struct Helper<9, <0, 1, 4, 9, 16, 25, 36, 49, 64>> : Helper<9 + 1, 0, 1, 4, 9, 16, 25, 36, 49, 64, 9 * 9> {
};
template<> struct Helper<10, <0, 1, 4, 9, 16, 25, 36, 49, 64, 81>> {
  static constexpr std::array<int, TABLE_SIZE> table = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81};
};

चूंकि सी ++ 17 इसे और अधिक आसानी से लिखा जा सकता है:

 
#include <iostream>
#include <array>

constexpr int TABLE_SIZE = 10;

constexpr std::array<int, TABLE_SIZE> table = [] { // OR: constexpr auto table
  std::array<int, TABLE_SIZE> A = {};
  for (unsigned i = 0; i < TABLE_SIZE; i++) {
    A[i] = i * i;
  }
  return A;
}();

enum  {
  FOUR = table[2] // compile time use
};

int main() {
  for (int i=0; i < TABLE_SIZE; i++) {
    std::cout << table[i]  << std::endl; // run time use
  }
  std::cout << "FOUR: " << FOUR << std::endl;
}

अधिक परिष्कृत उदाहरण दिखाने के लिए निम्नलिखित सूची में कोड को मूल्य गणना के लिए एक सहायक (अधिक जटिल संगणना की तैयारी में), तालिका विशिष्ट ऑफ़सेट और तालिका मानों के प्रकार के लिए एक टेम्पलेट तर्क के लिए विस्तारित किया गया है (उदाहरण के लिए uint8_t, uint16_t, ...)

                                                                
#include <iostream>
#include <array>

constexpr int TABLE_SIZE = 20;
constexpr int OFFSET = 12;

/**
 * Template to calculate a single table entry
 */
template <typename VALUETYPE, VALUETYPE OFFSET, VALUETYPE INDEX>
struct ValueHelper {
  static constexpr VALUETYPE value = OFFSET + INDEX * INDEX;
};

/**
 * Variadic template for a recursive helper struct.
 */
template<typename VALUETYPE, VALUETYPE OFFSET, int N = 0, VALUETYPE ...D>
struct Helper : Helper<VALUETYPE, OFFSET, N+1, D..., ValueHelper<VALUETYPE, OFFSET, N>::value> { };

/**
 * Specialization of the template to end the recursion when the table size reaches TABLE_SIZE.
 */
template<typename VALUETYPE, VALUETYPE OFFSET, VALUETYPE ...D>
struct Helper<VALUETYPE, OFFSET, TABLE_SIZE, D...> {
  static constexpr std::array<VALUETYPE, TABLE_SIZE> table = { D... };
};

constexpr std::array<uint16_t, TABLE_SIZE> table = Helper<uint16_t, OFFSET>::table;

int main() {
  for (int i = 0; i < TABLE_SIZE; i++) {
    std::cout << table[i] << std::endl;
  }
}

जिसे C++17 का उपयोग करके इस प्रकार लिखा जा सकता है:

#include <iostream>
#include <array>

constexpr int TABLE_SIZE = 20;
constexpr int OFFSET = 12;

template<typename VALUETYPE, VALUETYPE OFFSET>
constexpr std::array<VALUETYPE, TABLE_SIZE> table = [] { // OR: constexpr auto table
  std::array<VALUETYPE, TABLE_SIZE> A = {};
  for (unsigned i = 0; i < TABLE_SIZE; i++) {
    A[i] = OFFSET + i * i;
  }
  return A;
}();

int main() {
  for (int i = 0; i < TABLE_SIZE; i++) {
    std::cout << table<uint16_t, OFFSET>[i] << std::endl;
  }
}


अवधारणाएं

C++20 मानक ने C++ प्रोग्रामर्स को मेटा टेम्पलेट प्रोग्रामिंग, अवधारणाओं के लिए एक नया उपकरण दिया।[6] अवधारणाएँ (C++) प्रोग्रामर को प्रकार के लिए आवश्यकताओं को निर्दिष्ट करने की अनुमति देती हैं, ताकि टेम्पलेट का इन्स्टेन्शियशन संभव हो सके। कंपाइलर उस अवधारणा वाले टेम्पलेट की तलाश करता है जिसकी उच्चतम आवश्यकताएं हैं।

यहाँ टेम्पलेट मेटा प्रोग्रामिंग के साथ हल की गई प्रसिद्ध फ़िज़ बज़ समस्या का एक उदाहरण है।

#include <boost/type_index.hpp> // for pretty printing of types
#include <iostream>
#include <tuple>

/**
 * Type representation of words to print
 */
struct Fizz {};
struct Buzz {};
struct FizzBuzz {};
template<size_t _N> struct number { constexpr static size_t N = _N; };

/**
 * Concepts used to define condition for specializations
 */
template<typename Any> concept has_N = requires{ requires Any::N - Any::N == 0; };
template<typename A> concept fizz_c = has_N<A> && requires{ requires A::N % 3 == 0; };
template<typename A> concept buzz_c = has_N<A> && requires{ requires A::N % 5 == 0;};
template<typename A> concept fizzbuzz_c = fizz_c<A> && buzz_c<A>;

/**
 * By specializing `res` structure, with concepts requirements, proper instantiation is performed
 */
template<typename X> struct res;
template<fizzbuzz_c X> struct res<X> { using result = FizzBuzz; };
template<fizz_c X> struct res<X> { using result = Fizz; };
template<buzz_c X> struct res<X> { using result = Buzz; };
template<has_N X> struct res<X> { using result = X; };

/**
 * Predeclaration of concatenator
 */
template <size_t cnt, typename... Args> 
struct concatenator;

/**
 * Recursive way of concatenating next types
 */
template <size_t cnt, typename ... Args>
struct concatenator<cnt, std::tuple<Args...>> 
{ using type = typename concatenator<cnt - 1, std::tuple< typename res< number<cnt> >::result, Args... >>::type;};

/**
 * Base case
 */
template <typename... Args> struct concatenator<0, std::tuple<Args...>> { using type = std::tuple<Args...>;};

/**
 * Final result getter
 */
template<size_t Amount>
using fizz_buzz_full_template = typename concatenator<Amount - 1, std::tuple<typename res<number<Amount>>::result>>::type;

int main()
{
	// printing result with boost, so it's clear
	std::cout << boost::typeindex::type_id<fizz_buzz_full_template<100>>().pretty_name() << std::endl;
/*
Result:
	std::tuple<number<1ul>, number<2ul>, Fizz, number<4ul>, Buzz, Fizz, number<7ul>, number<8ul>, Fizz, Buzz, number<11ul>, Fizz, number<13ul>, number<14ul>, FizzBuzz, number<16ul>, number<17ul>, Fizz, number<19ul>, Buzz, Fizz, number<22ul>, number<23ul>, Fizz, Buzz, number<26ul>, Fizz, number<28ul>, number<29ul>, FizzBuzz, number<31ul>, number<32ul>, Fizz, number<34ul>, Buzz, Fizz, number<37ul>, number<38ul>, Fizz, Buzz, number<41ul>, Fizz, number<43ul>, number<44ul>, FizzBuzz, number<46ul>, number<47ul>, Fizz, number<49ul>, Buzz, Fizz, number<52ul>, number<53ul>, Fizz, Buzz, number<56ul>, Fizz, number<58ul>, number<59ul>, FizzBuzz, number<61ul>, number<62ul>, Fizz, number<64ul>, Buzz, Fizz, number<67ul>, number<68ul>, Fizz, Buzz, number<71ul>, Fizz, number<73ul>, number<74ul>, FizzBuzz, number<76ul>, number<77ul>, Fizz, number<79ul>, Buzz, Fizz, number<82ul>, number<83ul>, Fizz, Buzz, number<86ul>, Fizz, number<88ul>, number<89ul>, FizzBuzz, number<91ul>, number<92ul>, Fizz, number<94ul>, Buzz, Fizz, number<97ul>, number<98ul>, Fizz, Buzz>
*/
}


टेम्प्लेट मेटाप्रोग्रामिंग के लाभ और कमियां

कंपाइल-टाइम बनाम एक्ज़ीक्यूशन-टाइम ट्रेडऑफ़
यदि टेम्प्लेट मेटाप्रोग्रामिंग का एक बड़ा उपयोग किया जाता है।
सामान्य प्रोग्रामिंग
टेम्प्लेट मेटाप्रोग्रामिंग प्रोग्रामर को आर्किटेक्चर पर ध्यान केंद्रित करने और क्लाइंट कोड द्वारा आवश्यक किसी भी कार्यान्वयन की पीढ़ी को कंपाइलर को सौंपने की अनुमति देता है। इस प्रकार, टेम्प्लेट मेटाप्रोग्रामिंग वास्तव में सामान्य कोड को पूरा कर सकता है, जिससे कोड न्यूनीकरण और बेहतर रखरखाव की सुविधा मिलती है[citation needed].
पठनीयता
C++ 11 से पहले C++ के संबंध में, टेम्पलेट मेटाप्रोग्रामिंग के वाक्य-विन्यास और मुहावरे पारंपरिक C++ प्रोग्रामिंग की तुलना में गूढ़ थे, और टेम्पलेट मेटाप्रोग्राम को समझना बहुत मुश्किल हो सकता है।[7][8] लेकिन सी ++ 11 से आगे मूल्य गणना मेटाप्रोग्रामिंग के लिए सिंटैक्स कम और कम पठनीयता दंड के साथ सामान्य सी ++ के समान अधिक हो जाता है।

यह भी देखें

संदर्भ

  1. Scott Meyers (12 May 2005). Effective C++: 55 Specific Ways to Improve Your Programs and Designs. Pearson Education. ISBN 978-0-13-270206-5.
  2. See History of TMP on Wikibooks
  3. Veldhuizen, Todd L. (2003). "C++ टेम्प्लेट ट्यूरिंग पूर्ण हैं". CiteSeerX 10.1.1.14.3670. {{cite journal}}: Cite journal requires |journal= (help)
  4. "कॉन्स्टेक्सप्र - सी++ 11 में सामान्यीकृत निरंतर अभिव्यक्तियां - Cprogramming.com". www.cprogramming.com.
  5. "Iterator Facade - 1.79.0".
  6. "Constraints and concepts (since C++20) - cppreference.com". en.cppreference.com.
  7. Czarnecki, K.; O'Donnell, J.; Striegnitz, J.; Taha, Walid Mohamed (2004). "DSL implementation in metaocaml, template haskell, and C++" (PDF). University of Waterloo, University of Glasgow, Research Centre Julich, Rice University. C++ Template Metaprogramming suffers from a number of limitations, including portability problems due to compiler limitations (although this has significantly improved in the last few years), lack of debugging support or IO during template instantiation, long compilation times, long and incomprehensible errors, poor readability of the code, and poor error reporting. {{cite journal}}: Cite journal requires |journal= (help)
  8. Sheard, Tim; Jones, Simon Peyton (2002). "Template Meta-programming for Haskell" (PDF). ACM 1-58113-415-0/01/0009. Robinson's provocative paper identifies C++ templates as a major, albeit accidental, success of the C++ language design. Despite the extremely baroque nature of template meta-programming, templates are used in fascinating ways that extend beyond the wildest dreams of the language designers. Perhaps surprisingly, in view of the fact that templates are functional programs, functional programmers have been slow to capitalize on C++'s success {{cite journal}}: Cite journal requires |journal= (help)


बाहरी संबंध