সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টেশন - এটি কখন ব্যবহৃত হয়?


95

কয়েক সপ্তাহ বিরতির পরে, আমি টেমপ্লেটগুলি - ডেভিড ভ্যান্ডেভার্ডে এবং নিকোলাই এম জোসুটিসের সম্পূর্ণ নির্দেশিকা বইয়ের সাথে আমার টেমপ্লেটগুলির জ্ঞানকে প্রসারিত ও প্রসারিত করার চেষ্টা করছি এবং আমি এই মুহুর্তে যা বোঝার চেষ্টা করছি তা টেম্পলেটগুলির স্পষ্ট ইনস্ট্যান্টেশন ।

আমার মতো প্রক্রিয়াটির সাথে আসলে সমস্যা নেই তবে আমি এমন কোনও পরিস্থিতি কল্পনা করতে পারি না যেখানে আমি এই বৈশিষ্ট্যটি ব্যবহার করতে চাই বা ব্যবহার করতে চাই। যদি কেউ আমার কাছে এটি ব্যাখ্যা করতে পারে তবে আমি কৃতজ্ঞদের চেয়েও বেশি থাকব।

উত্তর:


67

Https://docs.microsoft.com/en-us/cpp/cpp/exp Clear-instantiation থেকে সরাসরি অনুলিপি করা হয়েছে :

আপনি প্রকৃতপক্ষে আপনার কোডটিতে এটি ব্যবহার না করে কোনও টেম্প্লেটেড ক্লাস বা ফাংশনের ইনস্ট্যান্টেশন তৈরি করতে সুস্পষ্ট ইনস্ট্যান্টেশন ব্যবহার করতে পারেন। কারণ এটি কার্যকর যখন আপনি লাইব্রেরি (.lib) ফাইল তৈরি করছেন যা বিতরণের জন্য টেম্পলেট ব্যবহার করে, অযথা টেম্পলেট সংজ্ঞাগুলি বস্তু (.obj) ফাইলগুলিতে রাখা হয় না।

(উদাহরণস্বরূপ, libstdc ++ এর সুস্পষ্ট ইনস্ট্যান্টেশন রয়েছে std::basic_string<char,char_traits<char>,allocator<char> >(যা এটি std::string) সুতরাং আপনি যতবার ফাংশন ব্যবহার করেন ততবার std::stringএকই ফাংশন কোডটি অবজেক্টে অনুলিপি করার প্রয়োজন হয় না The সংকলকটি কেবল লিবিস্টডিসি ++ তে লিখিত (লিঙ্ক) প্রয়োজন))


8
হ্যাঁ, এমএসভিসি সিআরটি গ্রন্থাগারগুলিতে চর এবং wchar_t এর জন্য বিশেষায়িত সমস্ত স্ট্রিম, লোকাল এবং স্ট্রিং ক্লাসগুলির জন্য স্পষ্টভাবে ইনস্ট্যান্টেশন রয়েছে। ফলস্বরূপ। লিব 5 মেগাবাইটের ওপরে।
হ্যানস প্যাস্যান্ট

4
সংকলকটি কীভাবে জানতে পারে যে টেম্পলেটটি স্পষ্টভাবে অন্য কোথাও ইনস্ট্যান্ট করা হয়েছে? এটি কি ক্লাস সংজ্ঞাটি জেনারেট করে না কারণ এটি উপলব্ধ?

@ স্টিং: যদি টেমপ্লেটটি তাত্ক্ষণিকভাবে বন্ধ করা হয় তবে প্রতীক টেবিলের মধ্যে functions ফাংশনগুলির একটি এন্ট্রি থাকবে।
কেনেটিএম

@ কেনি: আপনার অর্থ কি এটি ইতিমধ্যে একই টিইউতে ইনস্ট্যান্ট করা আছে? আমি ধরে নিব যে কোনও সংকলক একই টিউতে একাধিকবার একই বিশেষত্ব ইনস্ট্যান্ট না করার জন্য যথেষ্ট স্মার্ট। আমি ভেবেছিলাম সুস্পষ্ট তাত্ক্ষণিকতার সুবিধা (বিল্ডিং / লিঙ্ক বারের সাথে সম্পর্কিত) হ'ল যদি কোনও টিইউতে কোনও স্পেশালাইজেশন (স্পষ্টভাবে) ইনস্ট্যান্ট করা হয়, তবে এটি ব্যবহৃত অন্যান্য টিইউতে এটি ইনস্ট্যান্ট করা হবে না। না?

4
@ কেনি: আমি অন্তর্নিহিত তাত্পর্য প্রতিরোধের জন্য জিসিসি বিকল্প সম্পর্কে জানি, তবে এটি কোনও মানদণ্ড নয়। আমি যতদূর জানি ভিসি ++ এর মতো কোনও বিকল্প নেই। সুস্পষ্ট তাত্ক্ষণিক। সংকলন / লিঙ্ক বারগুলি উন্নত হিসাবে চিহ্নিত করা হয় (এমনকি বার্জনে দ্বারাও), তবে এটির উদ্দেশ্যটি সম্পাদনের জন্য, সংকলকটি অবশ্যই কোনওভাবে টেমপ্লেটগুলি স্পষ্টভাবে ইনস্ট্যান্ট করতে হবে না (উদাহরণস্বরূপ, জিসিসি পতাকা দ্বারা) বা দেওয়া উচিত নয় টেমপ্লেট সংজ্ঞা, কেবল একটি ঘোষণা। এই শব্দটি কি সঠিক? আমি কেবল বুঝতে চেষ্টা করছি যে কেন কেউ সুস্পষ্ট ইনস্ট্যান্টেশন ব্যবহার করবে (কংক্রিটের ধরণগুলি সীমাবদ্ধ না করে)

85

আপনি যদি কোনও টেম্পলেট শ্রেণীর সংজ্ঞা দেন যা আপনি কেবল কয়েকটি স্বতন্ত্র ধরণের জন্য কাজ করতে চান।

টেম্পলেট ঘোষণাকে হোল্ডার ফাইলে একটি সাধারণ শ্রেণীর মতো রাখুন।

সাধারণ শ্রেণীর মতো উত্স ফাইলে টেম্পলেট সংজ্ঞা রাখুন।

তারপরে, উত্স ফাইলটির শেষে, আপনি যে সংস্করণটি উপলভ্য হতে চান তা স্পষ্টভাবে ইনস্ট্যান্ট করুন।

নির্বোধ উদাহরণ:

// 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();
}

4
এটি কি ঠিক বলা যায় যে যদি সংকলকটির প্রদত্ত অনুবাদ ইউনিটে পুরো টেম্পলেট সংজ্ঞা (ফাংশন সংজ্ঞা সহ) থাকে তবে এটি যখন প্রয়োজন হয় তখন টেমপ্লেটের একটি বিশেষত্ব ইনস্ট্যান্ট করবে (সেই বিশেষত্বটি অন্য কোন টিউতে স্পষ্টতই ইনস্ট্যান্ট করা হয়েছে কিনা ) উদাহরণস্বরূপ, সুস্পষ্ট তাত্ক্ষণিকতার সংকলন / লিঙ্ক-টাইম সুবিধার ফসল কাটাতে, কোনওটিকে কেবলমাত্র টেম্পলেট ঘোষণার অন্তর্ভুক্ত করতে হবে যাতে সংকলক এটি ইনস্ট্যান্ট করতে না পারে?

4
@ ব্যবহারকারী 123456: সম্ভবত সংকলক নির্ভরশীল। তবে বেশিরভাগ পরিস্থিতিতে সম্ভবত সত্য।
মার্টিন ইয়র্ক

4
আপনার পূর্বনির্ধারিত ধরণের সংকলকটি স্পষ্টভাবে ইনস্ট্যান্টিত সংস্করণটি ব্যবহার করার কোনও উপায় আছে তবে আপনি যদি "অদ্ভুত / অপ্রত্যাশিত" ধরণের সাহায্যে টেম্পলেটটি ইনস্ট্যান্ট করার চেষ্টা করেন তবে এটি "স্বাভাবিক হিসাবে" কাজ করুন, যেখানে এটি কেবল প্রয়োজনীয় হিসাবে টেমপ্লেট ইনস্ট্যান্ট করে?
ডেভিড ডরিয়া

4
সুস্পষ্ট তাত্পর্যগুলি প্রকৃতপক্ষে ব্যবহৃত হচ্ছে তা নিশ্চিত করার জন্য ভাল চেক / পরীক্ষা কী হবে? অর্থাৎ এটি কাজ করছে, তবে আমি পুরোপুরি নিশ্চিত নই যে এটি কেবলমাত্র চাহিদা অনুসারে সমস্ত টেমপ্লেট ইনস্ট্যান্ট করছে না।
ডেভিড ডরিয়া

7
উপরের মন্তব্য মন্তব্যগুলির বেশিরভাগই আর সি ++ 11 সাল থেকে সত্য নয়: একটি স্পষ্ট তাত্ক্ষণিক বিবরণী (একটি বাহ্যিক টেম্পলেট) অন্তর্নিহিত প্রতিস্থাপনাকে বাধা দেয়: অন্যথায় কোনও সংঘাতের কারণ হতে পারে এমন কোডটি অন্য কোথাও প্রদত্ত স্পষ্ট ইনস্ট্যান্টেশন সংজ্ঞাটি ব্যবহার করতে হবে প্রোগ্রাম (সাধারণত, অন্য কোনও ফাইলে: এটি সংকলনের সময়গুলি হ্রাস করতে ব্যবহৃত হতে পারে) en.cppreferences.com/w/cpp/language/class_template
xaxxon

21

সুস্পষ্ট তাত্ক্ষণিকতা সংকলনের সময় এবং অবজেক্টের আকার হ্রাস করতে দেয়

এগুলি এটি সরবরাহ করতে পারে এমন বড় লাভ। তারা নীচের বিভাগগুলিতে বিস্তারিতভাবে বর্ণিত নিম্নলিখিত দুটি প্রভাব থেকে এসেছে:

  • বিল্ড সরঞ্জামগুলিকে পুনর্নির্মাণকারী অন্তর্ভুক্তকরণ থেকে রোধ করতে শিরোনামগুলি থেকে সংজ্ঞাগুলি সরান
  • অবজেক্টের নতুন সংজ্ঞা

শিরোনামগুলি থেকে সংজ্ঞাগুলি সরান

সুস্পষ্ট ইনস্ট্যান্টেশন আপনাকে .cpp ফাইলে সংজ্ঞা রাখতে দেয়।

সংজ্ঞাটি যখন শিরোনামে থাকে এবং আপনি এটিকে সংশোধন করেন, একটি বুদ্ধিমান বিল্ড সিস্টেম সমস্ত অন্তর্ভুক্তকারীকে পুনরায় সংকলন করবে, যা কয়েক ডজন ফাইল হতে পারে, সংকলনটি অসহনীয়ভাবে ধীর করে দেয়।

.Cpp ফাইলগুলিতে সংজ্ঞা স্থাপনের ফলে এমন ক্ষতি হয় যে বাহ্যিক গ্রন্থাগারগুলি তাদের নিজস্ব নতুন ক্লাসগুলির সাহায্যে টেমপ্লেটটি পুনরায় ব্যবহার করতে পারে না, তবে "অন্তর্ভুক্ত শিরোনামগুলি থেকে সংজ্ঞাগুলি সরিয়ে ফেলতে পারে তবে টেমপ্লেটগুলি বহিরাগত এপিআইও উন্মুক্ত করে" নীচে একটি কার্যপ্রণালী দেখায়।

নীচে কংক্রিট উদাহরণ দেখুন।

অবজেক্টের পুনঃনির্ধারণ লাভ: সমস্যাটি বোঝা

আপনি যদি একটি শিরোনাম ফাইলটিতে কেবলমাত্র একটি টেম্পলেটকে সম্পূর্ণরূপে সংজ্ঞায়িত করেন তবে প্রতিটি একক সংকলন ইউনিট যার মধ্যে শিরোনামটি অন্তর্ভুক্ত থাকে প্রতিটি পৃথক টেম্পলেট আর্গুমেন্ট ব্যবহারের জন্য টেমপ্লেটের নিজস্ব অন্তর্নিহিত অনুলিপি সংকলন করে।

এর অর্থ প্রচুর অকেজো ডিস্ক ব্যবহার এবং সংকলনের সময়।

এখানে একটি কংক্রিটের উদাহরণ দেওয়া আছে, যেখানে এই ফাইলগুলিতে এর ব্যবহারের কারণে উভয়ই 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স্থির করার সিদ্ধান্ত নিয়েছে।

সুতরাং আমরা দেখতে পাচ্ছি যে প্রতিটি একক পদ্ধতি ইনস্ট্যান্টেশনের জন্য একটি পৃথক বিভাগ তৈরি করা হয়েছে এবং তাদের প্রত্যেকে অবজেক্ট ফাইলগুলিতে অবশ্যই স্থান গ্রহণ করবে।

অবজেক্টের পুনরায় সংজ্ঞা সমস্যার সমাধান

এই সমস্যাটি সুস্পষ্ট তাত্ক্ষণিক ব্যবহারের মাধ্যমে বা এড়ানো যায়:

  • এইচপিপিতে সংজ্ঞা রাখুন এবং extern templateস্পষ্টভাবে তাত্ক্ষণিকভাবে চলতে চলেছে এমন প্রকারের জন্য এইচপিকে যুক্ত করুন।

    যেমন ব্যাখ্যা করা হয়েছে: বহির্মুখী টেম্পলেট (সি ++ 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, তবে মনে হয় যে আপনি এটির জন্য অন্তর্ভুক্তটি শিরোনামে যুক্ত করতে বাধ্য হয়েছেন, একটি অগ্রণী ঘোষণা যথেষ্ট নয়: বাহ্যিক টেম্পলেট এবং অসম্পূর্ণ প্রকারের ফলে শিরোনাম নির্ভরতা বাড়ে একটু.
  • সিপিপি ফাইলে সংজ্ঞাটি সরিয়ে, এইচপিপিতে কেবল ঘোষণা রেখে যান, অর্থাত্ আসল উদাহরণটি পরিবর্তন করুন:

    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তাদের সিপিপি ফাইলগুলিতে যুক্ত করতে হবে, যা প্রোগ্রামাররা সম্ভবত এটি করতে ভুলে যাবে।

এই সমাধানগুলির যে কোনও একটি সহ, 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উপায়ে undefined।

অন্তর্ভুক্ত শিরোলেখগুলি থেকে সংজ্ঞাগুলি সরান তবে টেমপ্লেটগুলি কেবলমাত্র শিরোনামের লাইব্রেরিতে একটি বাহ্যিক এপিআই প্রকাশ করে

আপনার লাইব্রেরি যদি কেবল শিরোনাম না হয় তবে extern templateপদ্ধতিটি কাজ করবে, যেহেতু প্রকল্পগুলি ব্যবহার করা কেবলমাত্র আপনার অবজেক্ট ফাইলে লিঙ্ক করবে, এতে সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টেশনের অবজেক্ট থাকবে।

তবে, কেবল শিরোনামের গ্রন্থাগারগুলির জন্য, যদি আপনি উভয়ই চান:

  • আপনার প্রকল্পের সংকলন গতি
  • অন্যদের এটির ব্যবহারের জন্য একটি বাহ্যিক গ্রন্থাগার API হিসাবে শিরোনামগুলি প্রকাশ করুন

তাহলে আপনি নিম্নলিখিতগুলির মধ্যে একটি ব্যবহার করতে পারেন:

    • 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।

সি ++ 20 মডিউল

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

আমি মনে করি এই বৈশিষ্ট্যটি উপলব্ধ হয়ে ওঠার সাথে সাথে এগিয়ে যাওয়ার সর্বোত্তম সেটআপ সরবরাহ করবে তবে আমি এখনও এটি পরীক্ষা করে দেখিনি কারণ এটি এখনও আমার জিসিসি 9.2.1 এ উপলব্ধ নেই।

স্পিডআপ / ডিস্ক সাশ্রয় পেতে আপনাকে এখনও স্পষ্ট তাত্ক্ষণিক কাজ করতে হবে তবে কমপক্ষে আমাদের "অন্তর্ভুক্ত শিরোনামগুলি থেকে সংজ্ঞাগুলি সরিয়ে ফেলুন তবে টেমপ্লেটগুলি একটি বাহ্যিক এআইপিও উন্মুক্ত করুন" এর জন্য একটি সমঝোতা সমাধান হবে যার জন্য প্রায় 100 বার জিনিস অনুলিপি করার প্রয়োজন হয় না।

প্রত্যাশিত ব্যবহার (সুস্পষ্ট উন্মাদনা ছাড়াই, সঠিক বাক্য গঠন কেমন হবে তা নিশ্চিত নয়, দেখুন: সি ++ 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, যার মধ্যে উত্সটির কিছু এলএলভিএম অন্তর্বর্তী প্রতিনিধিত্ব থাকতে হবে: সি ++ মডিউল সিস্টেমে টেমপ্লেটগুলি কীভাবে পরিচালিত হয়? যা এখনও টেমপ্লেট স্পেসিফিকেশন ঘটতে দেয়।

আপনার বিল্ডটিকে কীভাবে দ্রুত বিশ্লেষণ করবেন তা দেখার জন্য এটি টেমপ্লেট ইনস্ট্যান্টেশন থেকে অনেক উপার্জন পাবে কিনা

সুতরাং, আপনি একটি জটিল প্রকল্প পেয়েছেন এবং আপনি সিদ্ধান্ত নিতে চান যে টেম্পলেট ইনস্ট্যান্টেশনটি আসলে সম্পূর্ণ রিফেক্টরটি না করেই উল্লেখযোগ্য লাভ অর্জন করবে কিনা?

নীচের বিশ্লেষণগুলি আপনাকে সিদ্ধান্ত নিতে সহায়তা করতে পারে বা কমপক্ষে কমপক্ষে কিছু ধারণা ধার করে আপনি পরীক্ষার সময় প্রথমে রিফ্যাক্টর করার জন্য সবচেয়ে প্রতিশ্রুতিবদ্ধ বিষয়গুলি বেছে নিতে পারেন: আমার সি ++ অবজেক্ট ফাইলটি খুব বড়

# 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 অতিরিক্ত প্রচেষ্টা করা।

সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টিয়েশনের একটি গৌণ বোনাস: সহায়তা IDE গুলি তালিকা টেম্পলেট ইনস্ট্যান্টেশন

আমি খুঁজে পেয়েছি যে কিছু আইডিই যেমন একটিগ্রহের সমাধান করতে পারে না "ব্যবহৃত সমস্ত টেম্পলেট ইনস্ট্যান্টের একটি তালিকা"।

সুতরাং উদাহরণস্বরূপ, আপনি যদি একটি টেম্পলেট কোডের অভ্যন্তরে থাকেন এবং আপনি এই টেমপ্লেটের সম্ভাব্য মানগুলি খুঁজে পেতে চান তবে আপনাকে কনস্ট্রাক্টরের একের পর এক ব্যবহার ব্যবহার করতে হবে এবং সম্ভাব্য প্রকারগুলি একের পর এক করে করতে হবে।

তবে এক্সিলিপ ২০২০-০৩-তে আমি ক্লাসের নাম অনুসন্ধান করে সমস্ত ব্যবহার (সিটিআরএল + আল্ট + জি) অনুসন্ধান করে খুব সহজেই তাত্ক্ষণিক টেম্পলেটগুলি তালিকাভুক্ত করতে পারি, যা আমাকে উদাহরণস্বরূপ নির্দেশ করে:

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/e1c7c6634f2d5cdeafd2bdc79bcfbb2057cb04c4/cpp/animal_template.hpp#L15

আপনি IDE এর বাইরে অন্য গেরিলা কৌশল ব্যবহার করতে পারেন তবে তা 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

এটি সংকলক মডেলের উপর নির্ভর করে - বাহ্যত বোরল্যান্ড মডেল এবং সিএফ্রন্ট মডেল রয়েছে। এবং তারপরে এটি আপনার অভিপ্রায়ও নির্ভর করে - আপনি যদি কোনও গ্রন্থাগার লেখেন তবে আপনি (উপরে বর্ণিত হিসাবে) আপনার পছন্দসই বিশেষতাকে স্পষ্টভাবে ইনস্ট্যান্ট করতে পারেন।

জিএনইউ সি ++ পৃষ্ঠাটি এখানে মডেলগুলি সম্পর্কে আলোচনা করে https://gcc.gnu.org/onlinesocs/gcc-4.5.2/gcc/Template-Instantiation.html

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.