स्पष्ट टेम्पलेट तात्कालिकता - इसका उपयोग कब किया जाता है?


95

कुछ हफ़्ते के विराम के बाद, मैं टेम्प्लेट बुक के साथ टेम्प्लेट के अपने ज्ञान का विस्तार और विस्तार करने की कोशिश कर रहा हूं - डेविड वंदेवोर्डे और निकोलई एम। जोसुतिस द्वारा पूरी गाइड , और मैं इस पल को समझने की कोशिश कर रहा हूं ।

मुझे वास्तव में इस तरह के तंत्र के साथ कोई समस्या नहीं है, लेकिन मैं ऐसी स्थिति की कल्पना नहीं कर सकता हूं जिसमें मैं इस सुविधा का उपयोग करना चाहता हूं या करना चाहता हूं। अगर कोई मुझे समझा सकता है कि मैं आभारी रहूंगा।

जवाबों:


67

सीधे https://docs.microsoft.com/en-us/cpp/cpp/explicit-instantiation से कॉपी किया गया :

आप अपने कोड में वास्तव में इसका उपयोग किए बिना एक अस्थायी वर्ग या फ़ंक्शन का एक पल बनाने के लिए स्पष्ट तात्कालिकता का उपयोग कर सकते हैं। क्योंकि यह तब उपयोगी होता है जब आप लाइब्रेरी ( .lib ) फ़ाइलों का निर्माण करते हैं जो वितरण के लिए टेम्पलेट का उपयोग करते हैं , अनइंस्टैंटेड टेम्पलेट परिभाषाएँ ऑब्जेक्ट (.obj) फ़ाइलों में नहीं डाली जाती हैं।

(उदाहरण के लिए, libstdc ++ में हर बार जब आप फ़ंक्शन का उपयोग करते हैं , तो इसका स्पष्ट इंस्ट्रूमेंटेशन std::basic_string<char,char_traits<char>,allocator<char> >होता है std::string) std::string, समान फ़ंक्शन कोड को ऑब्जेक्ट्स में कॉपी करने की आवश्यकता नहीं होती है। कंपाइलर को केवल libstdc ++ को संदर्भित (लिंक) करने की आवश्यकता होती है।)


8
हाँ, MSVC CRT लाइब्रेरीज़ में सभी स्ट्रीम, लोकेल और स्ट्रिंग क्लासेस के लिए स्पष्ट इंस्टेंशन्स हैं, जो char और wchar_t के लिए विशेष हैं। परिणामी .lib 5 मेगाबाइट से अधिक है।
हंस पैशन

4
कंपाइलर को कैसे पता चलता है कि टेम्प्लेट को स्पष्ट रूप से तत्काल कहीं और लगाया गया है? क्या यह केवल वर्ग परिभाषा उत्पन्न करने वाला नहीं है क्योंकि यह उपलब्ध है?

@STING: यदि टेम्पलेट त्वरित है, तो प्रतीक तालिका में उन कार्यों का एक प्रवेश होगा।
kennytm

@ केनी: आपका मतलब है कि यह पहले से ही एक ही टीयू में त्वरित है? मुझे लगता है कि कोई भी कंपाइलर एक ही टीयू में एक से अधिक बार एक ही विशेषज्ञता को तुरंत नहीं करने के लिए पर्याप्त स्मार्ट है। मुझे लगा कि स्पष्ट तात्कालिकता (निर्माण / लिंक समय के संबंध में) का लाभ यह है कि यदि एक विशेषज्ञता (स्पष्ट रूप से) एक टीयू में त्वरित है, तो इसका उपयोग अन्य टीयू में तत्काल नहीं किया जाएगा जिसमें इसका उपयोग किया जाता है। नहीं?

4
@ केनी: मैं निहित तात्कालिकता को रोकने के लिए जीसीसी विकल्प के बारे में जानता हूं, लेकिन यह एक मानक नहीं है। जहाँ तक मुझे पता है VC ++ के पास ऐसा कोई विकल्प नहीं है। स्पष्ट उदाहरण। हमेशा संकलन / लिंक बार (ब्रेज़न द्वारा भी) में सुधार के रूप में टाउट किया जाता है, लेकिन इसके लिए उस उद्देश्य की पूर्ति के लिए, कंपाइलर को किसी भी तरह तात्कालिक तात्कालिक टेम्पलेट्स (जैसे, जीसीसी ध्वज के माध्यम से) नहीं पता होना चाहिए, या नहीं दिया जाना चाहिए। टेम्पलेट परिभाषा, केवल एक घोषणा। क्या यह ध्वनि सही है? मैं सिर्फ यह समझने की कोशिश कर रहा हूं कि कोई स्पष्ट तात्कालिकता (कंक्रीट प्रकारों को सीमित करने के अलावा) का उपयोग क्यों करेगा।

86

यदि आप एक टेम्प्लेट क्लास को परिभाषित करते हैं जिसे आप केवल स्पष्ट प्रकार के एक जोड़े के लिए काम करना चाहते हैं।

हेडर फ़ाइल में टेम्प्लेट घोषणा को सामान्य वर्ग की तरह रखें।

एक सामान्य फ़ाइल की तरह टेम्पलेट फ़ाइल को स्रोत फ़ाइल में रखें।

फिर, स्रोत फ़ाइल के अंत में, केवल उस संस्करण को स्पष्ट रूप से झटपट करें जो आप उपलब्ध होना चाहते हैं।

मूर्खतापूर्ण उदाहरण:

// StringAdapter.h
template<typename T>
class StringAdapter
{
     public:
         StringAdapter(T* data);
         void doAdapterStuff();
     private:
         std::basic_string<T> m_data;
};
typedef StringAdapter<char>    StrAdapter;
typedef StringAdapter<wchar_t> WStrAdapter;

स्रोत:

// StringAdapter.cpp
#include "StringAdapter.h"

template<typename T>
StringAdapter<T>::StringAdapter(T* data)
    :m_data(data)
{}

template<typename T>
void StringAdapter<T>::doAdapterStuff()
{
    /* Manipulate a string */
}

// Explicitly instantiate only the classes you want to be defined.
// In this case I only want the template to work with characters but
// I want to support both char and wchar_t with the same code.
template class StringAdapter<char>;
template class StringAdapter<wchar_t>;

मुख्य

#include "StringAdapter.h"

// Note: Main can not see the definition of the template from here (just the declaration)
//       So it relies on the explicit instantiation to make sure it links.
int main()
{
  StrAdapter  x("hi There");
  x.doAdapterStuff();
}

1
क्या यह कहना सही है कि यदि किसी दिए गए अनुवाद इकाई में कंपाइलर की पूरी टेम्प्लेट परिभाषा (फ़ंक्शन परिभाषा सहित) है, तो यह ज़रूरत पड़ने पर टेम्प्लेट के एक स्पेशिफिकेशन को तुरंत रोक देगा (चाहे उस स्पेशलाइज़ेशन को दूसरे टीयू में स्पष्ट रूप से इंस्टेंटिएट किया गया हो )? Ie, स्पष्ट तात्कालिकता के संकलन / लिंक-टाइम लाभों को पुनः प्राप्त करने के लिए, किसी को केवल टेम्पलेट घोषणा को शामिल करना होगा ताकि संकलक इसे तत्काल न कर सके ?

1
@ user123456: संभवतः संकलक निर्भर। लेकिन ज्यादातर स्थितियों में संभावना से अधिक सच है।
मार्टिन यॉर्क

1
क्या कंपाइलर आपके द्वारा पूर्व-निर्दिष्ट प्रकारों के लिए स्पष्ट रूप से तात्कालिक संस्करण का उपयोग करने का एक तरीका है, लेकिन फिर यदि आप टेम्पलेट को "अजीब / अप्रत्याशित" प्रकार से इंस्टेंट करने की कोशिश करते हैं, तो यह "सामान्य रूप से" काम करता है, जहां यह बस आवश्यकतानुसार टेम्प्लेट तैयार करता है?
डेविड डोरिया

2
यह सुनिश्चित करने के लिए एक अच्छा चेक / परीक्षण क्या होगा कि स्पष्ट तात्कालिक उपयोग वास्तव में किया जा रहा है? यानी यह काम कर रहा है, लेकिन मैं पूरी तरह से आश्वस्त नहीं हूं कि यह सिर्फ मांग पर सभी टेम्पलेट्स को तत्काल तैयार नहीं कर रहा है।
डेविड डोरिया

7
उपर्युक्त टिप्पणी चैटर में से अधिकांश अब सी +११ के बाद से सच नहीं है: एक स्पष्ट तात्कालिकता घोषणा (एक बाहरी टेम्पलेट) अंतर्निहित तात्कालिकता को रोकता है: कोड जो अन्यथा एक अंतर्निहित तात्कालिकता का कारण होगा स्पष्ट तात्कालिकता परिभाषा का उपयोग करना है जो कहीं और प्रदान की गई है प्रोग्राम (आम तौर पर, किसी अन्य फ़ाइल में: इसका उपयोग संकलन समय को कम करने के लिए किया जा सकता है) en.cppreference.com/w/cpp/language/class_template
xaxxon

21

स्पष्ट तात्कालिकता संकलन समय और ऑब्जेक्ट आकार को कम करने की अनुमति देता है

ये प्रमुख लाभ हैं जो इसे प्रदान कर सकते हैं। वे नीचे दिए गए वर्गों में विस्तार से वर्णित दो प्रभावों से आते हैं:

  • हेडर से परिभाषाओं को हटाने के लिए शामिल किए गए संस्थापकों के निर्माण से रोकने के लिए
  • ऑब्जेक्ट पुनर्परिभाषित

हेडर से परिभाषाएँ निकालें

स्पष्ट तात्कालिकता आपको .cpp फ़ाइल में परिभाषाएँ छोड़ने की अनुमति देती है।

जब परिभाषा शीर्षलेख पर होती है और आप इसे संशोधित करते हैं, तो एक बुद्धिमान बिल्ड सिस्टम सभी शामिलकर्ताओं को फिर से जोड़ देगा, जो दर्जनों फाइलें हो सकती हैं, जिससे संकलन असहनीय रूप से धीमा हो जाता है।

.Cpp फ़ाइलों में परिभाषाएँ डालने से नकारात्मक पक्ष यह है कि बाहरी लाइब्रेरीज़ अपनी नई कक्षाओं के साथ टेम्पलेट का पुन: उपयोग नहीं कर सकती हैं, लेकिन "इसमें शामिल हेडर से परिभाषाएँ निकालें, लेकिन टेम्पलेट्स को बाहरी API से बाहर निकाल दें" नीचे एक वर्कअराउंड दिखाता है।

नीचे ठोस उदाहरण देखें।

ऑब्जेक्ट पुनर्निर्देशन लाभ: समस्या को समझना

यदि आप सिर्फ हेडर फ़ाइल पर एक टेम्पलेट को पूरी तरह से परिभाषित करते हैं, तो हर एक संकलन इकाई जिसमें वह हेडर शामिल होता है, जो किए गए हर अलग टेम्पलेट तर्क उपयोग के लिए टेम्पलेट की अपनी अंतर्निहित प्रति को संकलित करता है।

इसका मतलब है कि बहुत सारे बेकार डिस्क उपयोग और संकलन समय।

यहां एक ठोस उदाहरण है, जिसमें उन फाइलों में इसके उपयोग के कारण दोनों main.cppऔर notmain.cppअंतर्निहित रूप से परिभाषित किया MyTemplate<int>गया है।

main.cpp

#include <iostream>

#include "mytemplate.hpp"
#include "notmain.hpp"

int main() {
    std::cout << notmain() + MyTemplate<int>().f(1) << std::endl;
}

notmain.cpp

#include "mytemplate.hpp"
#include "notmain.hpp"

int notmain() { return MyTemplate<int>().f(1); }

mytemplate.hpp

#ifndef MYTEMPLATE_HPP
#define MYTEMPLATE_HPP

template<class T>
struct MyTemplate {
    T f(T t) { return t + 1; }
};

#endif

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

int notmain();

#endif

गिटहब ऊपर

संकलन और देखने के प्रतीकों के साथ nm:

g++ -c -Wall -Wextra -std=c++11 -pedantic-errors -o notmain.o notmain.cpp
g++ -c -Wall -Wextra -std=c++11 -pedantic-errors -o main.o main.cpp
g++    -Wall -Wextra -std=c++11 -pedantic-errors -o main.out notmain.o main.o
echo notmain.o
nm -C -S notmain.o | grep MyTemplate
echo main.o
nm -C -S main.o | grep MyTemplate

आउटपुट:

notmain.o
0000000000000000 0000000000000017 W MyTemplate<int>::f(int)
main.o
0000000000000000 0000000000000017 W MyTemplate<int>::f(int)

से man nm, हम देखते हैं कि Wकमजोर प्रतीक का अर्थ है, जिसे जीसीसी ने चुना क्योंकि यह एक टेम्पलेट फ़ंक्शन है। कमजोर प्रतीक का मतलब है कि संकलित अंतर्निहित कोड के लिए MyTemplate<int>दोनों फाइलों पर संकलित किया गया था।

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

आउटपुट में संख्या का मतलब है:

  • 0000000000000000: अनुभाग के भीतर पता। यह शून्य है क्योंकि टेम्पलेट स्वचालित रूप से अपने स्वयं के अनुभाग में डाल दिए जाते हैं
  • 0000000000000017: उनके लिए उत्पन्न कोड का आकार

हम इसे थोड़ा और स्पष्ट रूप से देख सकते हैं:

objdump -S main.o | c++filt

जो समाप्त होता है:

Disassembly of section .text._ZN10MyTemplateIiE1fEi:

0000000000000000 <MyTemplate<int>::f(int)>:
   0:   f3 0f 1e fa             endbr64 
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   c:   89 75 f4                mov    %esi,-0xc(%rbp)
   f:   8b 45 f4                mov    -0xc(%rbp),%eax
  12:   83 c0 01                add    $0x1,%eax
  15:   5d                      pop    %rbp
  16:   c3                      retq

और _ZN10MyTemplateIiE1fEiवह नाम है MyTemplate<int>::f(int)>जिसका नाम c++filtतय नहीं किया गया है।

इसलिए हम देखते हैं कि प्रत्येक एकल विधि तात्कालिकता के लिए एक अलग खंड उत्पन्न होता है, और उनमें से प्रत्येक वस्तु फ़ाइलों में निश्चित रूप से स्थान लेता है।

ऑब्जेक्ट रिडिफाइनमेंट समस्या का समाधान

स्पष्ट तात्कालिकता का उपयोग करके इस समस्या से बचा जा सकता है और या तो:

  • hpp पर परिभाषा रखें और extern templateउन प्रकारों के लिए hpp पर जोड़ें, जो स्पष्ट रूप से त्वरित होने जा रहे हैं।

    जैसा कि समझाया गया है: बाहरी टेम्पलेट (C ++ 11) का उपयोग extern template पूरी तरह से परिभाषित टेम्पलेट को संकलन इकाइयों द्वारा तत्काल हमारे स्पष्ट तात्कालिकता को छोड़कर रोकता है। इस तरह, केवल हमारी स्पष्ट तात्कालिकता को अंतिम वस्तुओं में परिभाषित किया जाएगा:

    mytemplate.hpp

    #ifndef MYTEMPLATE_HPP
    #define MYTEMPLATE_HPP
    
    template<class T>
    struct MyTemplate {
        T f(T t) { return t + 1; }
    };
    
    extern template class MyTemplate<int>;
    
    #endif
    

    mytemplate.cpp

    #include "mytemplate.hpp"
    
    // Explicit instantiation required just for int.
    template class MyTemplate<int>;
    

    main.cpp

    #include <iostream>
    
    #include "mytemplate.hpp"
    #include "notmain.hpp"
    
    int main() {
        std::cout << notmain() + MyTemplate<int>().f(1) << std::endl;
    }
    

    notmain.cpp

    #include "mytemplate.hpp"
    #include "notmain.hpp"
    
    int notmain() { return MyTemplate<int>().f(1); }
    

    नकारात्मक पहलू:

    • यदि आप केवल लाइब्रेरी के हेडर हैं, तो आप बाहरी प्रोजेक्ट्स को अपनी स्पष्ट तात्कालिकता के लिए मजबूर करते हैं। यदि आप हेडर-ओनली लाइब्रेरी नहीं हैं, तो यह समाधान सबसे अच्छा है।
    • यदि टेम्प्लेट का प्रकार आपकी स्वयं की परियोजना में परिभाषित किया गया है और बिल्ट-इन की तरह नहीं है int, तो ऐसा लगता है कि आप हेडर पर इसके लिए शामिल करने के लिए मजबूर हैं, एक फॉरवर्ड घोषणा पर्याप्त नहीं है: बाहरी टेम्पलेट और अपूर्ण प्रकार यह हेडर निर्भरता को बढ़ाता है एक सा।
  • सीपीपी फ़ाइल पर परिभाषा को आगे बढ़ाते हुए, केवल घोषणा को hpp पर छोड़ दें, अर्थात मूल उदाहरण को संशोधित करें:

    mytemplate.hpp

    #ifndef MYTEMPLATE_HPP
    #define MYTEMPLATE_HPP
    
    template<class T>
    struct MyTemplate {
        T f(T t);
    };
    
    #endif
    

    mytemplate.cpp

    #include "mytemplate.hpp"
    
    template<class T>
    T MyTemplate<T>::f(T t) { return t + 1; }
    
    // Explicit instantiation.
    template class MyTemplate<int>;
    

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

  • एचपीपी पर परिभाषा रखें और extern templateहर शामिलकर्ता पर जोड़ें :

    mytemplate.cpp

    #include "mytemplate.hpp"
    
    // Explicit instantiation.
    template class MyTemplate<int>;
    

    main.cpp

    #include <iostream>
    
    #include "mytemplate.hpp"
    #include "notmain.hpp"
    
    // extern template declaration
    extern template class MyTemplate<int>;
    
    int main() {
        std::cout << notmain() + MyTemplate<int>().f(1) << std::endl;
    }
    

    notmain.cpp

    #include "mytemplate.hpp"
    #include "notmain.hpp"
    
    // extern template declaration
    extern template class MyTemplate<int>;
    
    int notmain() { return MyTemplate<int>().f(1); }
    

    नकारात्मक पक्ष: सभी शामिलकर्ताओं externको अपनी CPP फ़ाइलों को जोड़ना होगा, जो प्रोग्रामर संभवतः करना भूल जाएंगे।

उन समाधानों में से किसी के साथ, nmअब शामिल हैं:

notmain.o
                 U MyTemplate<int>::f(int)
main.o
                 U MyTemplate<int>::f(int)
mytemplate.o
0000000000000000 W MyTemplate<int>::f(int)

इसलिए हम देखते हैं कि केवल वांछित mytemplate.oका संकलन है MyTemplate<int>, जबकि notmain.oऔर main.oनहीं है क्योंकि Uअपरिभाषित का मतलब है।

शामिल हेडर से परिभाषाएँ निकालें, लेकिन हेडर-ओनली लाइब्रेरी में बाहरी एपीआई को भी एक्सपोज करें

यदि आपकी लाइब्रेरी केवल हेडर नहीं है, तो extern templateविधि काम करेगी, क्योंकि प्रोजेक्ट्स का उपयोग केवल आपकी ऑब्जेक्ट फ़ाइल से लिंक होगा, जिसमें स्पष्ट टेम्प्लेट इंस्टेंटेशन का ऑब्जेक्ट होगा।

हालांकि, हेडर केवल पुस्तकालयों के लिए, यदि आप दोनों को चाहते हैं:

  • अपने प्रोजेक्ट के संकलन को गति दें
  • इसका उपयोग करने के लिए अन्य के लिए बाहरी पुस्तकालय एपीआई के रूप में हेडर को उजागर करें

तो आप निम्न में से एक का प्रयास कर सकते हैं:

    • mytemplate.hpp: टेम्पलेट परिभाषा
    • mytemplate_interface.hpp: टेम्पलेट घोषणा केवल परिभाषाओं से मेल खाती है mytemplate_interface.hpp, कोई परिभाषा नहीं
    • mytemplate.cpp: शामिल करें mytemplate.hppऔर स्पष्ट झटपट बनाएं
    • main.cppऔर कोड बेस में हर जगह: शामिल हैं mytemplate_interface.hpp, नहींmytemplate.hpp
    • mytemplate.hpp: टेम्पलेट परिभाषा
    • mytemplate_implementation.hpp: इसमें हर वर्ग को शामिल किया गया है mytemplate.hppऔर externइसे तत्काल जोड़ा जाएगा
    • mytemplate.cpp: शामिल करें mytemplate.hppऔर स्पष्ट झटपट बनाएं
    • main.cppऔर कोड बेस में हर जगह: शामिल हैं mytemplate_implementation.hpp, नहींmytemplate.hpp

या कई हेडर के लिए शायद और भी बेहतर: अपने फ़ोल्डर के अंदर एक intf/ implफ़ोल्डर बनाएं includes/और mytemplate.hppहमेशा नाम के रूप में उपयोग करें ।

mytemplate_interface.hppदृष्टिकोण इस तरह दिखता है:

mytemplate.hpp

#ifndef MYTEMPLATE_HPP
#define MYTEMPLATE_HPP

#include "mytemplate_interface.hpp"

template<class T>
T MyTemplate<T>::f(T t) { return t + 1; }

#endif

mytemplate_interface.hpp

#ifndef MYTEMPLATE_INTERFACE_HPP
#define MYTEMPLATE_INTERFACE_HPP

template<class T>
struct MyTemplate {
    T f(T t);
};

#endif

mytemplate.cpp

#include "mytemplate.hpp"

// Explicit instantiation.
template class MyTemplate<int>;

main.cpp

#include <iostream>

#include "mytemplate_interface.hpp"

int main() {
    std::cout << MyTemplate<int>().f(1) << std::endl;
}

संकलित करें और चलाएं:

g++ -c -Wall -Wextra -std=c++11 -pedantic-errors -o mytemplate.o mytemplate.cpp
g++ -c -Wall -Wextra -std=c++11 -pedantic-errors -o main.o main.cpp
g++    -Wall -Wextra -std=c++11 -pedantic-errors -o main.out main.o mytemplate.o

आउटपुट:

2

उबुन्टु 18.04 में परीक्षण किया गया।

C ++ 20 मॉड्यूल

https://en.cppreference.com/w/cpp/language/modules

मुझे लगता है कि यह सुविधा उपलब्ध होते ही सबसे अच्छा सेटअप प्रदान करेगी, लेकिन मैंने इसे अभी तक चेक नहीं किया है क्योंकि यह अभी तक मेरे GCC 9.2.1 पर उपलब्ध नहीं है।

आपको अभी भी स्पीडअप / डिस्क सेविंग प्राप्त करने के लिए स्पष्ट तात्कालिकता करनी होगी, लेकिन कम से कम हमारे पास "शामिल हेडर से परिभाषाओं को हटा दें लेकिन टेम्पलेट्स को एक बाहरी एपीआई को उजागर करें" के लिए एक सनी समाधान होगा, जिसमें 100 बार चीजों को कॉपी करने की आवश्यकता नहीं है।

अपेक्षित उपयोग (बिना स्पष्ट अंतर्विरोध के, सुनिश्चित नहीं है कि सटीक वाक्यविन्यास कैसा होगा, देखें: C ++ 20 मॉड्यूल के साथ टेम्पलेट स्पष्ट तात्कालिकता का उपयोग कैसे करें? ) साथ कुछ हो:

helloworld.cpp

export module helloworld;  // module declaration
import <iostream>;         // import declaration
 
template<class T>
export void hello(T t) {      // export declaration
    std::cout << t << std::end;
}

main.cpp

import helloworld;  // import declaration
 
int main() {
    hello(1);
    hello("world");
}

और फिर https://quuxplusone.github.io/blog/2019/11/07/modular-hello-world/ पर संकलन का उल्लेख किया गया

clang++ -std=c++2a -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm
clang++ -std=c++2a -c -o helloworld.o helloworld.cpp
clang++ -std=c++2a -fprebuilt-module-path=. -o main.out main.cpp helloworld.o

तो इसमें से हम देखते हैं कि क्लैंग जादू में टेम्प्लेट इंटरफ़ेस + कार्यान्वयन को निकाल सकता है helloworld.pcm, जिसमें स्रोत के कुछ एलएलवीएम मध्यवर्ती प्रतिनिधित्व होना चाहिए: टेम्प्लेट को C ++ मॉड्यूल सिस्टम में कैसे हैंडल किया जाता है? जो अभी भी टेम्पलेट विनिर्देशन के लिए अनुमति देता है।

अपने निर्माण का विश्लेषण कैसे करें यह देखने के लिए कि क्या यह टेम्पलेट तात्कालिकता से बहुत कुछ हासिल करेगा

तो, आपको एक जटिल परियोजना मिल गई है और आप यह तय करना चाहते हैं कि क्या वास्तव में पूर्ण परावर्तन करने के बिना टेम्पलेट तात्कालिकता महत्वपूर्ण लाभ लाएगी?

नीचे दिए गए विश्लेषण से आपको निर्णय लेने में मदद मिल सकती है, या कम से कम सबसे अधिक होनहार वस्तुओं का चयन करने के लिए पहली बार रिफ्लेक्टर का उपयोग करें, कुछ विचारों को उधार लेकर: मेरी C ++ ऑब्जेक्ट फ़ाइल बहुत बड़ी है

# List all weak symbols with size only, no address.
find . -name '*.o' | xargs -I{} nm -C --size-sort --radix d '{}' |
  grep ' W ' > nm.log

# Sort by symbol size.
sort -k1 -n nm.log -o nm.sort.log

# Get a repetition count.
uniq -c nm.sort.log > nm.uniq.log

# Find the most repeated/largest objects.
sort -k1,2 -n nm.uniq.log -o nm.uniq.sort.log

# Find the objects that would give you the most gain after refactor.
# This gain is calculated as "(n_occurences - 1) * size" which is
# the size you would gain for keeping just a single instance.
# If you are going to refactor anything, you should start with the ones
# at the bottom of this list. 
awk '{gain = ($1 - 1) * $2; print gain, $0}' nm.uniq.sort.log |
  sort -k1 -n > nm.gains.log

# Total gain if you refactored everything.
awk 'START{sum=0}{sum += $1}END{print sum}' nm.gains.log

# Total size. The closer total gain above is to total size, the more
# you would gain from the refactor.
awk 'START{sum=0}{sum += $1}END{print sum}' nm.log

सपना: एक टेम्पलेट संकलक कैश

मुझे लगता है कि अगर हम निर्माण कर सकते हैं तो अंतिम समाधान होगा:

g++ --template-cache myfile.o file1.cpp
g++ --template-cache myfile.o file2.cpp

और फिर myfile.oस्वचालित रूप से फ़ाइलों में पहले से संकलित टेम्पलेट्स का पुन: उपयोग करेगा।

इसका मतलब प्रोग्रामर्स पर 0 अतिरिक्त प्रयास करने के अलावा आपके निर्माण प्रणाली में उस अतिरिक्त CLI विकल्प को पारित करना होगा।

स्पष्ट टेम्पलेट तात्कालिकता का एक माध्यमिक बोनस: आईडीई सूची टेम्पलेट तात्कालिकता में मदद करें

मैंने पाया है कि कुछ आईडीई जैसे कि ग्रहण "उपयोग किए गए सभी टेम्पलेट तात्कालिकता की एक सूची" को हल नहीं कर सकता है।

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

लेकिन ग्रहण २०२०-०३ पर मैं आसानी से क्लास के नाम पर सभी यूजेज (Ctrl + Alt + G) खोज कर, जो मुझे इंगित करता है, खोज करके स्पष्ट रूप से तत्काल टेम्पलेट्स सूचीबद्ध कर सकते हैं:

template <class T>
struct AnimalTemplate {
    T animal;
    AnimalTemplate(T animal) : animal(animal) {}
    std::string noise() {
        return animal.noise();
    }
};

सेवा:

template class AnimalTemplate<Dog>;

यहाँ एक डेमो है: https://github.com/cirosantilli/ide-test-projects/blob/e1c7c6634f2d5cdeafd2bdc79bcfb20bcb2057c04c4/cpp/animal_template.hpp#L15

एक और गुरिल्ला तकनीक जिसे आप आईडीई के बाहर उपयोग कर सकते हैं, लेकिन nm -Cअंतिम निष्पादन योग्य और टेम्पलेट नाम को चलाने के लिए होगा :

nm -C main.out | grep AnimalTemplate

जो इस तथ्य की ओर सीधे इशारा करता है कि Dogतात्कालिकता में से एक था:

0000000000004dac W AnimalTemplate<Dog>::noise[abi:cxx11]()
0000000000004d82 W AnimalTemplate<Dog>::AnimalTemplate(Dog)
0000000000004d82 W AnimalTemplate<Dog>::AnimalTemplate(Dog)

1

यह संकलक मॉडल पर निर्भर करता है - जाहिरा तौर पर बोरलैंड मॉडल और सीफ्रंट मॉडल है। और फिर यह आपके इरादे पर भी निर्भर करता है - यदि आप एक पुस्तकालय लिख रहे हैं, तो आप (जैसा कि ऊपर उल्लिखित है) स्पष्ट रूप से इच्छित विशेषज्ञता को तुरंत रद्द कर सकते हैं।

GNU c ++ पृष्ठ यहां मॉडलों की चर्चा करता है https://gcc.gnu.org/oniltocs/gcc-4.5.2/gcc/Template-Instantiation.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.