বাহ্যিক টেম্পলেট ব্যবহার করা (সি ++ 11)


116

চিত্র 1: ফাংশন টেম্পলেট

TemplHeader.h

template<typename T>
void f();

TemplCpp.cpp

template<typename T>
void f(){
   //...
}    
//explicit instantation
template void f<T>();

Main.cpp

#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
    f<char>();
    return 0;
}

এটি কি ব্যবহারের সঠিক উপায় extern template, বা আমি চিত্র 2 এর মতো কেবল শ্রেণিবদ্ধ টেম্পলেটগুলির জন্য এই কীওয়ার্ডটি ব্যবহার করব?

চিত্র 2: শ্রেণি টেম্পলেট

TemplHeader.h

template<typename T>
class foo {
    T f();
};

TemplCpp.cpp

template<typename T>
void foo<T>::f() {
    //...
}
//explicit instantation
template class foo<int>;

Main.cpp

#include "TemplHeader.h"
extern template class foo<int>();
int main() {
    foo<int> test;
    return 0;
}

আমি জানি যে এই সমস্তগুলি একটি হেডার ফাইলে রাখা ভাল, তবে আমরা যদি একাধিক ফাইলে একই পরামিতিগুলির সাহায্যে টেম্পলেটগুলি ইনস্ট্যান্ট করি তবে আমরা একাধিক একই সংজ্ঞা পেয়েছি এবং সংকলক ত্রুটিগুলি এড়ানোর জন্য সেগুলি সমস্ত (একটি ব্যতীত) সরিয়ে ফেলবে। আমি কীভাবে ব্যবহার করব extern template? আমরা কি এটি কেবল ক্লাসের জন্য ব্যবহার করতে পারি, বা আমরা এটি কার্যকারিতার জন্যও ব্যবহার করতে পারি?

এছাড়াও চিত্র 1 এবং চিত্র 2 এমন একটি সমাধানে প্রসারিত হতে পারে যেখানে টেমপ্লেটগুলি একক শিরোলেখ ফাইলের মধ্যে থাকে। সেক্ষেত্রে extern templateএকাধিক একই তাত্ক্ষণিক ঘটনা এড়াতে আমাদের কীওয়ার্ডটি ব্যবহার করতে হবে। এটি কি কেবল ক্লাস বা ফাংশনগুলির জন্য?


3
এটি মোটেও বাহ্যিক টেম্পলেটগুলির সঠিক ব্যবহার নয় ... এটি এমনকি সংকলন করে না
দানি

আপনি আরও কিছু পরিষ্কারভাবে (এক) প্রশ্নের বাক্যবিন্যাস করতে কিছু সময় নিতে পারেন? আপনি কি জন্য কোড পোস্ট করছেন? আমি এটি সম্পর্কিত কোনও প্রশ্ন দেখতে পাচ্ছি না। এছাড়াও, extern template class foo<int>();একটি ভুল মত মনে হচ্ছে।
সেভ

@ দানি> এটি আমার ভিজ্যুয়াল স্টুডিওতে সংক্ষিপ্তসার বার্তা ব্যতীত ২০১০ তে ঠিক সূক্ষ্ম সংকলন করেছে: সতর্কতা 1 সতর্কতা সি 4231: নন-স্ট্যান্ডার্ড এক্সটেনশন ব্যবহৃত হয়েছে: টেম্পলেট স্পষ্ট ইনস্ট্যান্টেশনের আগে 'বহিরাগত'
কোডকিডি

2
@ এই প্রশ্নটি খুব সহজ: কীভাবে, এবং কখন বহিরাগত টেম্পলেট কীওয়ার্ড ব্যবহার করবেন? (বাহ্যিক টেম্পলেটটি সি ++ 0 এক্স নতুন ভবিষ্যতের বিটিডব্লিউ) আপনি বলেছেন "এছাড়াও, বহিরাগত টেম্পলেট শ্রেণি foo <int> (); এটি একটি ভুল বলে মনে হচ্ছে" " না এটি নয়, আমার কাছে নতুন সি ++ বই রয়েছে এবং এটি আমার বইয়ের উদাহরণ।
কোডকিডি

1
@ কোডেকিডি: তারপরে ভিজ্যুয়াল স্টুডিওটি সত্যই বোকা .. দ্বিতীয়টির মধ্যে প্রোটোটাইপ বাস্তবায়নের সাথে মেলে না, এবং আমি যদি ()এটি স্থিরও করি তবে এটি বাহ্যিক লাইনের নিকটে 'প্রত্যাশিত অযোগ্য-আইডি' বলেছে । আপনার বই এবং ভিজ্যুয়াল স্টুডিও উভয়ই ভুল, আরও বেশি স্ট্যান্ডার্ড কমপ্লায়েন্ট কম্পাইলার যেমন জি ++ বা ক্ল্যাং ব্যবহার করার চেষ্টা করুন এবং আপনি সমস্যাটি দেখতে পাবেন।
দানি

উত্তর:


181

আপনি কেবল extern templateতখনই কম্পাইলারটিকে কোনও টেম্পলেট ইনস্ট্যান্টেট না করার জন্য ব্যবহার করতে পারেন যখন আপনি জানেন যে এটি অন্য কোথাও ইনস্ট্যান্ট করা হবে। এটি সংকলন সময় এবং বস্তুর ফাইলের আকার হ্রাস করতে ব্যবহৃত হয়।

উদাহরণ স্বরূপ:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}

// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}

// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

এটি নিম্নলিখিত অবজেক্ট ফাইলগুলির ফলাফল করবে:

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

যদি উভয় ফাইলই এক সাথে সংযুক্ত থাকে তবে একটি void ReallyBigFunction<int>()ফেলে দেওয়া হবে, ফলে সংকলনের সময় এবং অবজেক্ট ফাইলের আকার নষ্ট হবে।

সংকলন সময় এবং অবজেক্ট ফাইল আকার নষ্ট না করার জন্য, একটি externকীওয়ার্ড রয়েছে যা সংকলকটিকে কোনও টেম্পলেট ফাংশন সংকলন করে না। আপনার এটি ব্যবহার করা উচিত যদি এবং আপনি যদি জানেন তবে এটি অন্য কোথাও একই বাইনারিতে ব্যবহৃত হয়।

এতে পরিবর্তন source2.cppকরা হচ্ছে :

// source2.cpp

#include "header.h"
extern template void ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

নিম্নলিখিত অবজেক্ট ফাইলগুলির ফলাফল হবে:

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

যখন এই উভয়কেই এক সাথে সংযুক্ত করা হবে তখন দ্বিতীয় অবজেক্ট ফাইলটি কেবল প্রথম বস্তু ফাইল থেকে প্রতীকটি ব্যবহার করবে। বাতিল করার দরকার নেই এবং সময় এবং বস্তুর ফাইলের আকারের অপচয় হবে না।

এটি কেবলমাত্র কোনও প্রকল্পের মধ্যেই ব্যবহার করা উচিত, যেমন আপনি যখন vector<int>একাধিকবারের মতো কোনও টেম্পলেট ব্যবহার করেন তখন আপনার externউত্স ফাইল ব্যতীত অন্য সমস্ত ক্ষেত্রে ব্যবহার করা উচিত ।

এটি ক্লাসে এবং এক হিসাবে ফাংশন এবং এমনকি টেমপ্লেটের সদস্য ফাংশনগুলিতে প্রযোজ্য।


2
@ কোডেকিডি: ভিজুয়াল স্টুডিও এর দ্বারা কী বোঝায় সে সম্পর্কে আমার কোনও ধারণা নেই। আপনি যদি সর্বাধিক সি ++ 11 কোডটি সঠিকভাবে কাজ করতে চান তবে আপনার আরও কমপ্লায়েন্ট কম্পাইলার ব্যবহার করা উচিত।
দানি

4
@ দানি: আমি এখনও অবধি পড়া বাহ্যিক টেম্পলেটগুলির সর্বোত্তম ব্যাখ্যা!
পিট্রো

90
"আপনি যদি অন্য কোথাও একই বাইনারি ব্যবহার করতে জানেন।" এটি পর্যাপ্ত বা প্রয়োজনীয়ও নয়। আপনার কোডটি "দুর্বৃত্ত, কোনও ডায়াগনস্টিকের প্রয়োজন নেই"। আপনাকে অন্য টিইউয়ের অন্তর্নিহিত ইনস্ট্যান্টেশনের উপর নির্ভর করার অনুমতি দেওয়া হচ্ছে না (সংকলকটিকে এটিকে আরও অনুকূল করার অনুমতি দেওয়া হয়েছে, অনেকটা ইনলাইন ফাংশনের মতো)। একটি স্পষ্ট তাত্ক্ষণিকতা অন্য টিইউতে সরবরাহ করতে হবে।
জোহানেস স্কাউব -

32
আমি উল্লেখ করতে চাই যে এই উত্তরটি সম্ভবত ভুল, এবং আমি এটি দ্বারা কামড়েছি। ভাগ্যক্রমে জোহানিসের মন্তব্যে বেশ কয়েকটি ভোট পেয়েছে এবং আমি এবার এ দিকে বেশি মনোযোগ দিয়েছি। আমি কেবল ধরে নিতে পারি যে এই প্রশ্নের পক্ষে বেশিরভাগ ভোটার আসলে এই ধরণের টেম্পলেটগুলি একাধিক সংকলন ইউনিটগুলিতে বাস্তবায়ন করেনি (যেমনটি আমি আজ করেছি) ... কমপক্ষে ঝাঁকুনির জন্য, এই টেম্পলেট সংজ্ঞাগুলিকে একমাত্র নিশ্চিত করার উপায় আপনার হেডার! সতর্কাবস্থা!
স্টিভেন লু

6
@ জোহানেস শ্যাব-লিটব, আপনি কি আরও কিছুটা ব্যাখ্যা করতে পারেন বা আরও ভাল উত্তর দিতে পারেন? আমি নিশ্চিত না যে আমি আপনার আপত্তিগুলি পুরোপুরি বুঝতে পেরেছি কিনা।
অ্যান্ড্রি

48

উইকিপিডিয়ায় সর্বোত্তম বর্ণনা রয়েছে

সি ++ 03 তে, যখনই কোনও অনুবাদ ইউনিটে সম্পূর্ণ নির্দিষ্ট টেম্পলেটটির মুখোমুখি হয় তখন সংকলকটিকে অবশ্যই একটি টেম্পলেট ইনস্ট্যান্ট করতে হবে। যদি টেম্পলেটটি বহু অনুবাদ ইউনিটে একই ধরণের সাথে ইনস্ট্যান্ট হয় তবে এটি নাটকীয়ভাবে সংকলনের বার বাড়িয়ে তুলতে পারে। এটি C ++ 03 এ প্রতিরোধ করার কোনও উপায় নেই, সুতরাং সি ++ 11 বহিরাগত ডেটা ঘোষণার সাথে সাদৃশ্য বহিরাগত টেম্পলেট ঘোষণাগুলি প্রবর্তন করেছিল।

সি ++ 03 এর এই সংশ্লেষটি কোনও টেমপ্লেট ইনস্ট্যান্ট করতে সংকলককে বাধ্য করতে:

  template class std::vector<MyClass>;

সি ++ 11 এখন এই সিনট্যাক্স সরবরাহ করে:

  extern template class std::vector<MyClass>;

যা সংকলককে এই অনুবাদ ইউনিটে টেমপ্লেট ইনস্ট্যান্ট না করতে বলে।

সতর্কবার্তা: nonstandard extension used...

মাইক্রোসফ্ট ভিসি ++ ইতিমধ্যে কয়েক বছর ধরে এই বৈশিষ্ট্যটির একটি অ-মানক সংস্করণ ব্যবহার করেছেন (সি ++ 03 তে)। সংকলকটি সেই কোড সহ পোর্টেবিলিটি সমস্যাগুলি রোধ করতে সতর্ক করে যা বিভিন্ন সংকলকগুলিতে পাশাপাশি সংকলন করা প্রয়োজন।

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


আপনার উত্তরটি দেখার জন্য টিএনএক্স, সুতরাং এই অ্যাক্টিকুলটির অর্থ কী "বাহ্যিক টেম্পলেট" ভবিষ্যতে সম্পূর্ণরূপে ভিএস 2010 এর জন্য কাজ করে এবং আমরা কেবল সতর্কতাটিকে উপেক্ষা করতে পারি? (উদাহরণস্বরূপ বার্তাকে অগ্রাহ্য করার জন্য প্রগমা ব্যবহার করে) এবং উপকূলে থাকুন যে ভিএমসি ++ তে সময় মতো টেমপ্লেটটি আর ইনস্ট্যান্ট করা হয় না। কম্পাইলার। ধন্যবাদ।
কোডকিডি

4
"... যা এই অনুবাদ ইউনিটে টেমপ্লেট ইনস্ট্যান্ট না করা সংকলককে বলে " " আমি এটা সত্য মনে করি না। শ্রেণীর সংজ্ঞায় সংজ্ঞায়িত যে কোনও পদ্ধতি ইনলাইন হিসাবে গণ্য হয়েছে, সুতরাং এসটিএল বাস্তবায়ন যদি std::vector(সকলেরই বেশিরভাগ ক্ষেত্রে নিশ্চিত হয়) এর জন্য ইনলাইন পদ্ধতিগুলি ব্যবহার করে তবে externতার কোনও প্রভাব নেই।
আন্দ্রেস হাফারবার্গ

হ্যাঁ, এই উত্তরটি বিভ্রান্তিকর। এমএসএফটি ডক: "বিশেষায়নের বাহ্যিক কীওয়ার্ডটি কেবল শ্রেণীর শরীরের বাইরে সংজ্ঞায়িত সদস্য ফাংশনগুলিতে প্রযোজ্য the শ্রেণীর ঘোষণার ভিতরে সংজ্ঞায়িত ফাংশনগুলি ইনলাইন ফাংশন হিসাবে বিবেচিত হয় এবং সর্বদা তাত্ক্ষণিক হয় are" দুর্ভাগ্যক্রমে ভিএসে সমস্ত এসটিএল ক্লাস (সর্বশেষ চেক করা হয়েছিল 2017) এর কেবল ইনলাইন পদ্ধতি রয়েছে।
0kcats

যে সব ইনলাইন ঘোষণা জন্য যেখানে তারা উঠা নির্বিশেষে যায়, সবসময় @ 0kcats
sehe

@sehe স্ট্যান্ড :: ভেক্টর উদাহরণ সহ উইকির রেফারেন্স এবং একই উত্তরে এমএসভিসির একটি রেফারেন্স একজনকে বিশ্বাস করে যে এমএসভিসিতে বহিরাগত স্ট্যান্ড :: ভেক্টর ব্যবহারে কিছুটা সুবিধা হতে পারে, যদিও এখন পর্যন্ত কোনও ব্যবস্থা নেই। এটি স্ট্যান্ডার্ডের প্রয়োজন কিনা তা নিশ্চিত নয়, অন্য সংকলকগুলিরও একই সমস্যা রয়েছে।
0kcats

7

extern template টেমপ্লেট ঘোষণা সম্পূর্ণ হলেই প্রয়োজন needed

এটি অন্যান্য উত্তরে ইঙ্গিত করা হয়েছিল, তবে আমি মনে করি না যে এটির পক্ষে যথেষ্ট জোর দেওয়া হয়েছিল।

এর অর্থ হ'ল ওপিএস উদাহরণগুলিতে, extern templateএর কোনও প্রভাব নেই কারণ শিরোলেখগুলিতে টেম্পলেট সংজ্ঞাগুলি অসম্পূর্ণ ছিল:

  • void f();: শুধু ঘোষণা, কোন শরীর
  • class foo: পদ্ধতি ঘোষণা করে f()তবে তার কোনও সংজ্ঞা নেই

সুতরাং আমি extern templateনির্দিষ্ট ক্ষেত্রে সুনির্দিষ্ট সংজ্ঞাটি অপসারণের পরামর্শ দিচ্ছি : ক্লাসগুলি সম্পূর্ণরূপে সংজ্ঞায়িত হলে আপনার কেবল সেগুলি যুক্ত করা দরকার।

উদাহরণ স্বরূপ:

TemplHeader.h

template<typename T>
void f();

TemplCpp.cpp

template<typename T>
void f(){}

// Explicit instantiation for char.
template void f<char>();

Main.cpp

#include "TemplHeader.h"

// Commented out from OP code, has no effect.
// extern template void f<T>(); //is this correct?

int main() {
    f<char>();
    return 0;
}

প্রতীকগুলি সংকলন এবং দেখুন nm:

g++ -std=c++11 -Wall -Wextra -pedantic -c -o TemplCpp.o TemplCpp.cpp
g++ -std=c++11 -Wall -Wextra -pedantic -c -o Main.o Main.cpp
g++ -std=c++11 -Wall -Wextra -pedantic -o Main.out Main.o TemplCpp.o
echo TemplCpp.o
nm -C TemplCpp.o | grep f
echo Main.o
nm -C Main.o | grep f

আউটপুট:

TemplCpp.o
0000000000000000 W void f<char>()
Main.o
                 U void f<char>()

এবং তারপরে man nmআমরা দেখতে পাই এর Uঅর্থ অপরিবর্তিত, সুতরাং সংজ্ঞাটি কেবল TemplCppপছন্দসইভাবেই থেকে যায়।

এই সমস্তগুলি সম্পূর্ণ শিরোনামের ঘোষণার ব্যবসায়ের দিকে ফোটে:

  • upsides:
    • বহিরাগত কোডটি নতুন ধরণের সাথে আমাদের টেমপ্লেট ব্যবহার করতে দেয়
    • আমরা অবজেক্ট ব্লাট দিয়ে ভাল থাকলে স্পষ্ট তাত্ক্ষণিকতা যুক্ত না করার বিকল্প আমাদের আছে
  • মূল্যবান:
    • যখন এই শ্রেণিটি বিকাশ করা হচ্ছে, শিরোনাম বাস্তবায়ন পরিবর্তনগুলি স্মার্ট বিল্ড সিস্টেমগুলিকে সমস্ত অন্তর্ভুক্তকারীকে পুনর্নির্মাণে পরিচালিত করবে, যা অনেকগুলি ফাইল হতে পারে
    • যদি আমরা অবজেক্ট ফাইল ব্লোট এড়াতে চাই, আমাদের কেবল সুস্পষ্ট ইনস্ট্যানটিশনগুলিই করতে হবে না (অসম্পূর্ণ শিরোনামের ঘোষণার সাথে একই) তবে extern templateপ্রতিটি অন্তর্ভুক্তকারীকে যুক্ত করতে হবে, যা প্রোগ্রামাররা সম্ভবত করতে ভুলে যাবে

এর আরও উদাহরণ এখানে দেখানো হয়েছে: সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টেশন - এটি কখন ব্যবহৃত হয়?

যেহেতু বড় প্রকল্পগুলিতে সংকলনের সময়টি এত সমালোচনামূলক তাই আমি বহুলাংশে অসম্পূর্ণ টেম্পলেট ঘোষণার সুপারিশ করব, যদি না বাহ্যিক পক্ষগুলি তাদের কোডগুলি নিজস্ব জটিল কাস্টম শ্রেণীর সাহায্যে আপনার কোডটি পুনরায় ব্যবহার না করে।

এবং সেক্ষেত্রে বিল্ড টাইম সমস্যাটি এড়াতে আমি প্রথমে পলিমারফিজমটি ব্যবহার করার চেষ্টা করব এবং লক্ষণীয় পারফরম্যান্স লাভ করা সম্ভব হলে কেবলমাত্র টেমপ্লেটগুলি ব্যবহার করব।

উবুন্টুতে পরীক্ষিত 18.04।


4

টেমপ্লেটগুলির সাথে পরিচিত সমস্যাটি হ'ল কোড ব্লোটিং, যা প্রতিটি মডিউলগুলিতে শ্রেণীর সংজ্ঞা তৈরির ফলাফল যা ক্লাস টেম্পলেট বিশেষায়নের জন্য আহ্বান জানায়। এটি প্রতিরোধ করতে, C ++ 0x দিয়ে শুরু করে, কেউ শ্রেণীর টেম্পলেট বিশেষায়নের সামনে বহিরাগত কীওয়ার্ডটি ব্যবহার করতে পারে

#include <MyClass>
extern template class CMyClass<int>;

টেমপ্লেট শ্রেণীর সুস্পষ্ট তাত্পর্যটি কেবলমাত্র একটি একক অনুবাদ ইউনিটে ঘটানো উচিত, এটি টেমপ্লেট সংজ্ঞা (মাইক্লাস। সিপ্পি) সহ পছন্দনীয় rable

template class CMyClass<int>;
template class CMyClass<float>;

0

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

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