টেমপ্লেটগুলি কেবলমাত্র শিরোলেখ ফাইলটিতে প্রয়োগ করা যেতে পারে?


1774

সি ++ স্ট্যান্ডার্ড লাইব্রেরি থেকে উদ্ধৃতি : একটি টিউটোরিয়াল এবং হ্যান্ডবুক :

এই মুহুর্তে টেমপ্লেটগুলি ব্যবহারের একমাত্র পোর্টেবল উপায় হ'ল ইনলাইন ফাংশনগুলি ব্যবহার করে শিরোনাম ফাইলগুলিতে এগুলি প্রয়োগ করা।

কেন?

(স্পষ্টকরণ: শিরোনাম ফাইলগুলি কেবল পোর্টেবল সমাধান নয় But তবে এগুলি সর্বাধিক সুবিধাজনক পোর্টেবল সমাধান)


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

7
বইয়ের মেয়াদ শেষ।
gerardw

1
একটি টেম্পলেট কোনও ফাংশনের মতো নয় যা বাইট কোডে সংকলন করা যায়। এই জাতীয় ফাংশন উত্পন্ন করার জন্য এটি কেবল একটি প্যাটার্ন। আপনি যদি নিজের নিজের কোনও টেমপ্লেটকে * .cpp ফাইলে রেখে দেন তবে সংকলনের কিছুই নেই। তদুপরি, এক্সপ্লিটাইট ইনস্ট্যান্সেশন আসলে কোনও টেম্পলেট নয়, তবে টেমপ্লেটটি বাইরে রেখে কোনও ফাংশন তৈরির প্রারম্ভিক বিন্দু যা * .obj ফাইলে শেষ হয়।
dgrat

5
আমি কি কেবল
একাই

উত্তর:


1553

ক্যাভেট: শিরোনামের ফাইলে প্রয়োগকরণ স্থাপন করা প্রয়োজন হয় না , এই উত্তরটির শেষে বিকল্প সমাধান দেখুন।

যাইহোক, আপনার কোডটি ব্যর্থ হওয়ার কারণটি হ'ল, কোনও টেম্পলেট ইনস্ট্যান্ট করার সময় সংকলক প্রদত্ত টেমপ্লেট যুক্তি দিয়ে একটি নতুন শ্রেণি তৈরি করে। উদাহরণ স্বরূপ:

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f; 

এই লাইনটি পড়ার সময়, সংকলকটি একটি নতুন শ্রেণি তৈরি করবে (আসুন এটি কল করুন FooInt), যা নিম্নলিখিতগুলির সমান:

struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

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

এর সাধারণ সমাধান হ'ল হেডার ফাইলে টেমপ্লেট ঘোষণা লিখুন, তারপরে একটি বাস্তবায়ন ফাইলে ক্লাসটি প্রয়োগ করুন (উদাহরণস্বরূপ .tpp), এবং শিরোনামের শেষে এই বাস্তবায়ন ফাইলটি অন্তর্ভুক্ত করুন।

Foo.h

template <typename T>
struct Foo
{
    void doSomething(T param);
};

#include "Foo.tpp"

Foo.tpp

template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}

এইভাবে, বাস্তবায়ন এখনও ঘোষণা থেকে পৃথক করা হয়, তবে সংকলকটিতে অ্যাক্সেসযোগ্য।

বিকল্প সমাধান

আর একটি সমাধান হ'ল প্রয়োগটি পৃথক করে রাখা, এবং আপনার প্রয়োজন সমস্ত টেম্পলেট দৃষ্টান্ত স্পষ্টভাবে ইনস্ট্যান্ট করুন:

Foo.h

// no implementation
template <typename T> struct Foo { ... };

Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

যদি আমার ব্যাখ্যাটি যথাযথভাবে পরিষ্কার না হয় তবে আপনি এই বিষয়টির উপর C ++ সুপার-এফএকিউ দেখতে পারেন


96
প্রকৃতপক্ষে সুস্পষ্ট ইনস্ট্যান্টেশনটি একটি .cpp ফাইলে থাকা দরকার যা ফুটের সমস্ত সদস্য ফাংশনের সংজ্ঞা অ্যাক্সেস করে, শিরোনামের পরিবর্তে।
মানকারসে

11
"সংকলকটির টেমপ্লেট যুক্তি দিয়ে এগুলি ইনস্ট্যান্ট করার জন্য পদ্ধতিগুলির বাস্তবায়নের অ্যাক্সেস থাকা দরকার (এই ক্ষেত্রে প্রযোজ্য) these এই বাস্তবায়নগুলি যদি শিরোনামে না থাকে তবে এগুলি অ্যাক্সেসযোগ্য হত না" তবে কেন বাস্তবায়ন হয় .cpp ফাইলটি সংকলকের অ্যাক্সেসযোগ্য নয়? একটি সংকলক .cpp তথ্য অ্যাক্সেস করতে পারে, কীভাবে এটি তাদের .obj ফাইলগুলিতে পরিণত করবে? সম্পাদনা: এই প্রশ্নের উত্তরটি এই
উত্তরটিতে

31
আমি মনে করি না যে এটি এই প্রশ্নের ব্যাখ্যা দেয় যে স্পষ্টভাবে, মূল বিষয়টি স্পষ্টতই সংকলন ইউএনআইটি-র সাথে সম্পর্কিত যা এই পোস্টে উল্লেখ করা হয়নি

6
@ গ্যাবসন: স্ট্র্টস এবং ক্লাসগুলি ব্যতিক্রমগুলির সমতুল্য যে ক্লাসগুলির জন্য ডিফল্ট অ্যাক্সেস মডিফায়ারটি "ব্যক্তিগত" হয়, তবে এটি স্ট্র্টসের জন্য সর্বজনীন। কিছু অন্যান্য ছোট পার্থক্য রয়েছে যা আপনি এই প্রশ্নটি দেখে শিখতে পারেন ।
লুক টুরাইল

3
এই উত্তরটির একেবারে শুরুতে আমি একটি বাক্য যুক্ত করেছি যাতে স্পষ্ট হয় যে প্রশ্নটি একটি মিথ্যা ভিত্তির উপর ভিত্তি করে। যদি কেউ জিজ্ঞাসা করে "এক্স সত্য কেন?" যখন এক্স সত্য নয়, আমাদের দ্রুত সেই অনুমানটিকে প্রত্যাখ্যান করা উচিত।
অ্যারন ম্যাকডেইড

250

এখানে প্রচুর সঠিক উত্তর রয়েছে তবে আমি এটি যুক্ত করতে চেয়েছিলাম (সম্পূর্ণতার জন্য):

আপনি যদি বাস্তবায়ন সিপিপি ফাইলের নীচে, টেম্পলেটটি ব্যবহার করবেন এমন সমস্ত ধরণের স্পষ্টভাবে ইনস্ট্যান্টেশন করে থাকেন, লিঙ্কারটি তাদের যথারীতি খুঁজে পেতে সক্ষম হবে।

সম্পাদনা: সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টের উদাহরণ যুক্ত করা। টেমপ্লেট সংজ্ঞায়িত হওয়ার পরে ব্যবহৃত হয়েছে এবং সমস্ত সদস্য ফাংশন সংজ্ঞায়িত করা হয়েছে।

template class vector<int>;

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

উপরের উদাহরণটি মোটামুটি অকেজো, যেহেতু ভেক্টর সম্পূর্ণ শিরোনামগুলিতে সংজ্ঞায়িত হয়, কেবলমাত্র যখন কোনও সাধারণ অন্তর্ভুক্ত ফাইল (প্রাকম্পাইল্ড শিরোনাম?) ব্যবহার করে extern template class vector<int>যাতে এটি অন্য সমস্ত (1000?) ফাইলগুলিতে ভেক্টর ব্যবহার করে তা ইনস্ট্যান্ট করা থেকে বিরত রাখে।


51
বিতৃষ্ণা। ভাল উত্তর, কিন্তু কোন বাস্তব পরিষ্কার সমাধান। কোনও টেম্পলেটটির জন্য সমস্ত সম্ভাব্য প্রকারের তালিকা তৈরি করা কোনও টেম্পলেট যা বলে মনে করা হচ্ছে তা দিয়ে যায় না।
জিমিনিয়ন

6
এটি অনেক ক্ষেত্রে ভাল হতে পারে তবে সাধারণত টেমপ্লেটের উদ্দেশ্যটি ভেঙে দেয় যা আপনাকে typeম্যানুয়ালি তালিকাভুক্ত না করে ক্লাসটি ব্যবহার করার অনুমতি দেয় ।
টোমা জ্যাটো - মনিকা

7
vectorএটি একটি ভাল উদাহরণ নয় কারণ একটি ধারক সহজাতভাবে "সমস্ত" প্রকারকে লক্ষ্যবস্তু করে। তবে এটি খুব ঘন ঘন ঘটে যায় যে আপনি টেমপ্লেটগুলি তৈরি করেন যা কেবলমাত্র নির্দিষ্ট ধরণের নির্দিষ্ট সংখ্যার জন্য ব্যবহৃত হয়, উদাহরণস্বরূপ সংখ্যাসূচক প্রকারগুলি: int8_t, int16_t, int32_t, uint8_t, uint16_t ইত্যাদি this , তবে সম্পূর্ণ ধরণের সেটগুলির জন্য তাদের স্পষ্টভাবে ইনস্ট্যান্ট করাও সম্ভব এবং আমার মতে, প্রস্তাবিত recommended
আঙ্কেলজিভ

টেমপ্লেট সংজ্ঞায়িত হওয়ার পরে ব্যবহৃত হয়েছে, "এবং সমস্ত সদস্যের কার্যকারিতা সংজ্ঞায়িত করা হয়েছে"। ধন্যবাদ!
ভিট ভোল্ট

1
আমার মনে হচ্ছে আমি কিছু মিস করছি ... আমি ক্লাসের .cppফাইলে দুটি প্রকারের জন্য স্পষ্ট ইনস্ট্যান্টেশন রেখেছি এবং দুটি ইনস্ট্যান্টেশন অন্য .cppফাইলগুলি থেকে উল্লেখ করা হয়েছে , এবং এখনও সদস্যগুলির সন্ধান পাওয়া যায়নি এমন লিংক ত্রুটি পেয়েছি।
ওড়ফিশ

248

এটি পৃথক সংকলনের প্রয়োজনীয়তার কারণেই এবং টেমপ্লেটগুলি ইনস্ট্যান্টেশন-স্টাইলের বহুবচন রয়েছে।

একটি ব্যাখ্যার জন্য কংক্রিটের আরও কাছে যেতে দিন। বলুন আমি নীচের ফাইলগুলি পেয়েছি:

  • foo.h
    • এর ইন্টারফেস ঘোষণা করে class MyClass<T>
  • foo.cpp
    • বাস্তবায়ন সংজ্ঞায়িত class MyClass<T>
  • bar.cpp
    • ব্যবহারসমূহ MyClass<int>

পৃথক সংকলন অর্থ আমি কম্পাইল করতে সক্ষম হওয়া উচিত foo.cpp থেকে স্বাধীনভাবে bar.cpp । সংকলক প্রতিটি সংকলন ইউনিটে সম্পূর্ণ স্বতন্ত্রভাবে বিশ্লেষণ, অপ্টিমাইজেশন এবং কোড জেনারেশনের সমস্ত কঠোর পরিশ্রম করে; আমাদের পুরো প্রোগ্রাম বিশ্লেষণ করার দরকার নেই। এটি কেবলমাত্র লিঙ্কার যা একবারে পুরো প্রোগ্রামটি পরিচালনা করতে হবে এবং লিঙ্কারের কাজটি যথেষ্ট সহজ।

bar.cpp এমনকি অস্তিত্ব যখন আমি কম্পাইল দরকার নেই foo.cpp , কিন্তু আমি এখনও লিঙ্ক করতে সক্ষম হওয়া উচিত foo.o আমি ইতিমধ্যে সঙ্গে একসঙ্গে ছিল bar.o পুনরায় কম্পাইল করতে ছাড়াই, আমি কেবল মাত্র উত্পাদিত করেছি foo বিন্যাস .cppfoo.cpp এমনকি ডায়নামিক লাইব্রেরিতে সংকলিত হতে পারে, foo.cpp ছাড়াই অন্য কোথাও বিতরণ করা যায় এবং আমি foo.cpp লেখার কয়েক বছর পরে তারা কোডের সাথে লিঙ্কযুক্ত

"ইনস্ট্যান্টেশন-স্টাইল পলিমারফিজম" এর অর্থ হল যে টেমপ্লেটটি MyClass<T>আসলে একটি জেনেরিক শ্রেণি নয় যা কোনও কোডের সাথে সংকলিত হতে পারে যা কোনও মূল্যের জন্য কাজ করতে পারে T। যে বক্সিং যেমন ওভারহেড যেমন যোগ হবে, allocators এবং কন্সট্রাকটর, ইত্যাদি সি ++ টেমপ্লেট উদ্দেশ্য লিখতে থাকার এড়াতে হয় ফাংশন পয়েন্টার পাস প্রয়োজন মতো প্রায় একই class MyClass_int, class MyClass_floatইত্যাদি, কিন্তু এখনও কম্পাইল কোড যে সঙ্গে শেষ পাবে বেশিরভাগ যেন আমরা ছিল প্রত্যেকটি সংস্করণ আলাদাভাবে লিখিত। সুতরাং একটি টেমপ্লেট আক্ষরিকভাবে একটি টেম্পলেট; একটি বর্গ টেমপ্লেট না , একটি বর্গ প্রতিটি জন্য একটি নতুন শ্রেণী তৈরি করার জন্য একটি রেসিপি Tআমরা এনকাউন্টার। কোনও টেম্পলেট কোডে সংকলন করা যায় না, কেবলমাত্র টেমপ্লেট ইনস্ট্যান্ট করার ফলাফল সংকলন করা যায়।

সুতরাং যখন foo.cpp সংকলিত হয়, তখন সংকলকটি বার.cpp দেখতে পাবে না যে MyClass<int>এটি প্রয়োজনীয়। এটি টেমপ্লেটটি দেখতে পারে MyClass<T>, তবে এটি এর জন্য কোড নির্গত করতে পারে না (এটি একটি টেম্পলেট, কোনও শ্রেণি নয়)। এবং বার. cpp সংকলিত হয়ে গেলে, সংকলকটি দেখতে পারে যে এটির একটি তৈরি করা দরকার MyClass<int>তবে এটি টেমপ্লেটটি দেখতে পাবে না MyClass<T>(কেবলমাত্র তার ইন্টারফেসটি foo.h এ ) যাতে এটি তৈরি করতে পারে না।

যদি foo.cpp নিজেই ব্যবহার করে MyClass<int>তবে তার জন্য কোডটি foo.cpp সংকলনের সময় উত্পন্ন হবে , সুতরাং যখন বার.ও foo.o এর সাথে যুক্ত হবে তখন সেগুলি আপ করা যাবে এবং কাজ করবে। আমরা একটি বাস্তব টেমপ্লেট লিখে .cpp ফাইলে টেমপ্লেট ইনস্ট্যান্টেশনের একটি সীমাবদ্ধ সেটটি মঞ্জুর করার জন্য সেই বাস্তবতাকে ব্যবহার করতে পারি। তবে বার কোড পিপিপির পক্ষে এই টেম্পলেটটিকে একটি টেম্পলেট হিসাবে ব্যবহার করার এবং এটি যে ধরণের পছন্দ তা পছন্দ করে তা ইনস্ট্যান্ট করার কোনও উপায় নেই ; এটি কেবলমাত্র টেম্পলেটেড শ্রেণীর পূর্ব-বিদ্যমান সংস্করণগুলি ব্যবহার করতে পারে যা foo.cpp এর লেখক ভেবেছিলেন।

আপনি ভাবতে পারেন যে কোনও টেমপ্লেট সংকলন করার সময় সংকলকটির "সমস্ত সংস্করণ উত্পন্ন করা উচিত" এর সাথে লিঙ্ক চলাকালীন কখনই ফিল্টার আউট ব্যবহার করা হয় না। বিশাল ওভারহেড এবং চূড়ান্ত অসুবিধাগুলি বাদ দিয়ে এ জাতীয় পদ্ধতির মুখোমুখি হতে হবে কারণ পয়েন্টার এবং অ্যারেগুলির মতো "টাইপ মডিফায়ার" বৈশিষ্ট্যগুলি কেবল বিল্ট-ইন টাইপগুলিকেও অসীম ধরণের সংখ্যার জন্ম দেয়, যখন আমি এখন আমার প্রোগ্রামটি প্রসারিত করি তখন কী হয়? যোগ করে:

  • baz.cpp
    • ঘোষণা এবং প্রয়োগ class BazPrivate, এবং ব্যবহারMyClass<BazPrivate>

এটির কোনও সম্ভাব্য উপায় নেই যে আমরা না হলে এটি কাজ করতে পারে

  1. প্রোগ্রামে যখনই আমরা কোনও নতুন ফাইল পরিবর্তন করি তখন প্রতিবার foo.cpp কে পুনরায় সংকলন করতে হয় , যদি এটির মধ্যে একটি নতুন উপন্যাস ইনস্ট্যান্টেশন যুক্ত হয়MyClass<T>
  2. আবশ্যক যে baz.cpp এর সম্পূর্ণ টেমপ্লেট (সম্ভবত শিরোনামের মাধ্যমে অন্তর্ভুক্ত) রয়েছে MyClass<T>, যাতে সংকলক baz.cppMyClass<BazPrivate> সংকলনের সময় উত্পন্ন করতে পারে ।

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


50
জোর দেওয়া উদ্ধৃতি একটি টেম্পলেট আক্ষরিকভাবে একটি টেম্পলেট; ক্লাসের টেম্পলেটটি কোনও শ্রেণি নয়, এটি প্রতিটি টি-এর জন্য নতুন ক্লাস তৈরির জন্য একটি রেসিপি
v.oddou

আমি জানতে চাই, ক্লাসের শিরোনাম বা উত্স ফাইল ব্যতীত অন্য কোথাও থেকে সুস্পষ্ট ইনস্ট্যান্টেশনগুলি করা সম্ভব? উদাহরণস্বরূপ, সেগুলি মেইন.পি.পি.
gromit190

1
@ বিগার আপনার সম্পূর্ণ টেম্পলেট প্রয়োগের অ্যাক্সেস রয়েছে এমন কোনও ফাইল থেকে এটি করতে সক্ষম হওয়া উচিত (হয় কারণ এটি একই ফাইলটিতে বা শিরোনামের মাধ্যমে রয়েছে)।
বেন

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

1
ভাবেন এইভাবে ভাবেন ... আপনি যদি টেমপ্লেট ব্যবহার না করে থাকেন (আপনার যা প্রয়োজন তা দক্ষতার সাথে কোড করার জন্য), তবে আপনি কেবল সেই শ্রেণীর কয়েকটি সংস্করণ সরবরাহ করতে চাইবেন। সুতরাং আপনার কাছে 3 টি বিকল্প রয়েছে। 1)। টেমপ্লেট ব্যবহার করবেন না। (অন্যান্য শ্রেণি / ক্রিয়াকলাপের মতো, কেউই পরোয়া করে না যে অন্যরা প্রকারগুলি পরিবর্তন করতে পারে না) 2)। টেমপ্লেট এবং ডকুমেন্ট ব্যবহার করুন যা তারা ব্যবহার করতে পারে। 3)। তাদের পুরো বাস্তবায়ন (উত্স) বোনাস 4) দিন। তারা যদি আপনার ক্লাসের অন্য কোনও থেকে কোনও টেম্পলেট তৈরি করতে চান তবে তাদের পুরো উত্স দিন;)
পুডল

81

টেমপ্লেটগুলি বস্তু কোডে আসলে সংকলন করার আগে সংকলক দ্বারা তা ইনস্ট্যান্ট করা দরকার । টেম্পলেট আর্গুমেন্টগুলি জানা থাকলেই এই ইনস্ট্যান্টেশনটি অর্জন করা সম্ভব। এখন এমন একটি দৃশ্য কল্পনা করুন যেখানে কোনও টেম্পলেট ফাংশনটি ঘোষিত হয় a.h, সংজ্ঞায়িত হয় a.cppএবং এতে ব্যবহৃত হয় b.cpp। কখন a.cppসংকলন করা হয়, এটি অগত্যা জানা যায় না যে আসন্ন সংকলনটির b.cppজন্য টেমপ্লেটের একটি উদাহরণ প্রয়োজন হবে, কোন নির্দিষ্ট উদাহরণটি তা হতে দেওয়া যাক। আরও শিরোনাম এবং উত্স ফাইলগুলির জন্য, পরিস্থিতিটি আরও জটিল হয়ে উঠতে পারে।

কেউ যুক্তি দিতে পারেন যে টেমপ্লেটের সমস্ত ব্যবহারের জন্য সংকলকগুলিকে "সামনের দিকে তাকানোর" জন্য আরও চৌকস করে তোলা যেতে পারে, তবে আমি নিশ্চিত যে পুনরাবৃত্ত হওয়া বা অন্যথায় জটিল পরিস্থিতি তৈরি করা কঠিন হবে না sure আফাইক, সংকলকরা এই ধরণের চেহারা আগে করেন না। অ্যান্টন যেমন উল্লেখ করেছেন, কিছু সংকলক টেম্পলেট তাত্পর্যগুলির স্পষ্ট রফতানি ঘোষণাকে সমর্থন করে তবে সমস্ত সংকলক এটি সমর্থন করে না (এখনও?)?


1
"রফতানি" মানসম্পন্ন, তবে এটি বাস্তবায়ন করা খুব কঠিন তাই সংকলক দলগুলির বেশিরভাগই এখনও করেনি।
ভাভা

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

2
সুতরাং আমি মনে করি না রফতানি 'এখনও' প্রয়োগ করা হয়নি। এটি আর কতটা সময় নেয় এবং কতটুকু লাভ হয়েছিল তা দেখার পরে এটি সম্ভবত ইডিজি ছাড়া অন্য কারও দ্বারা করা হবে না
পিটার

3
যদি এটি আপনার আগ্রহী হয় তবে কাগজটিকে "কেন আমরা রফতানি করতে পারি না" বলা হয়, এটি তার ব্লগে তালিকাভুক্ত হয়েছে ( getw.ca/publications ) তবে সেখানে কোনও পিডিএফ নেই (একটি দ্রুত গুগল যদিও এটি চালু করতে পারে)
পিটার

1
ঠিক আছে, ভাল উদাহরণ এবং ব্যাখ্যা জন্য ধন্যবাদ। যদিও আমার প্রশ্ন এখানে: সংকলক কেন টেম্পলেট বলা হয় তা নির্ধারণ করতে পারে না এবং সংজ্ঞা ফাইল সংকলনের আগে এই ফাইলগুলি প্রথমে সংকলন করে? আমি কল্পনা করতে পারি এটি একটি সাধারণ ক্ষেত্রে করা যেতে পারে ... আন্তঃনির্ভরতা উত্তরটি কি দ্রুত গতিতে অর্ডার করবে?
ভ্লাদ

62

আসলে, সি ++ 11 পূর্বে মান সংজ্ঞায়িত exportশব্দ যে would এটা একটা হেডার ফাইলে টেমপ্লেট ডিক্লেয়ার সম্ভব করতে এবং সেগুলি অন্য কোথাও বাস্তবায়ন।

জনপ্রিয় সংকলকগুলির কেউই এই কীওয়ার্ডটি প্রয়োগ করেনি। আমি কেবল একমাত্র জানতে পারি হ'ল এডিসন ডিজাইন গ্রুপ দ্বারা রচিত ফ্রন্টএন্ড, যা কমেউ সি ++ সংকলক দ্বারা ব্যবহৃত হয়। অন্য সকলকে আপনার হেডার ফাইলগুলিতে টেম্পলেটগুলি লেখার প্রয়োজন ছিল, কারণ সংকলকটির সঠিক তাত্ক্ষণিকতার জন্য টেমপ্লেট সংজ্ঞা প্রয়োজন (অন্যরা ইতিমধ্যে দেখিয়েছে)।

ফলস্বরূপ, আইএসও সি ++ স্ট্যান্ডার্ড কমিটি exportসি ++ 11 সহ টেম্পলেটগুলির বৈশিষ্ট্যটি সরিয়ে নেওয়ার সিদ্ধান্ত নিয়েছে ।


6
... আর বছর দুয়েক পরে, আমি পরিশেষে বোঝা কি exportআসলে যেত দেওয়া আমাদের, এবং কি না ... আর এখন আমি মনপ্রাণ দিয়ে EDG মানুষের সাথে সম্মত হন: এটা আমাদের আনা হতো না যা বেশীর ভাগ মানুষ (নিজেকে '11 সালে অন্তর্ভুক্ত) ভাবেন এটি করবে, এবং সি ++ স্ট্যান্ডার্ডটি এটি ছাড়া ভাল।
দেবসোলার

4
@ দেভসোলার: এই কাগজটি রাজনৈতিক, পুনরাবৃত্তি এবং খারাপভাবে লেখা। এটি সেখানে সাধারণ স্তরের গদ্য নয়। অযৌক্তিকভাবে দীর্ঘ এবং বিরক্তিকর, মূলত দশ গুণ পৃষ্ঠাতে তিন বার একই জিনিস বলা। তবে আমি এখন জানিয়েছি যে রফতানি রফতানি নয়। এটি একটি ভাল ইন্টেল!
v.oddou

1
@ ভি.ডডু: ভাল বিকাশকারী এবং ভাল প্রযুক্তিবিদ লেখক দুটি পৃথক দক্ষ দক্ষতা সেট। কেউ কেউ দুটোই করতে পারে, অনেকেই পারে না। ;-)
দেবসোলার

@ v.oddou কাগজটি কেবল খারাপভাবে লেখা হয়নি, এটি বিশৃঙ্খলাবদ্ধ। এছাড়াও এটি বাস্তবতার স্পিন: রফতানির পক্ষে আসলে চরম দৃments় যুক্তিগুলি এমনভাবে মিশ্রিত হয় যেগুলি রফতানির বিপক্ষে হয়: "রফতানির উপস্থিতিতে স্ট্যান্ডার্ডে অসংখ্য ওডিআরলেটেড গর্ত আবিষ্কার করা। রফতানির আগে, ওডিআর লঙ্ঘনগুলি সংকলক দ্বারা সনাক্ত করা যায়নি। এখন এটি প্রয়োজনীয় কারণ আপনাকে বিভিন্ন অনুবাদ ইউনিট থেকে অভ্যন্তরীণ ডেটা স্ট্রাকচারগুলি একত্রিত করতে হবে এবং যদি তারা প্রকৃতপক্ষে বিভিন্ন জিনিস উপস্থাপন করে তবে আপনি তাদের একত্রিত করতে পারবেন না, তাই আপনাকে চেকিং করতে হবে। "
কৌতুহলী

" হ'ল অবশ্যই এটি যুক্ত করার সময় এটি কোন অনুবাদ ইউনিটে ছিল " দুহ। যখন আপনি খোঁড়া যুক্তিগুলি ব্যবহার করতে বাধ্য হন, তখন আপনার কোনও যুক্তি নেই। অবশ্যই আপনি নিজের ত্রুটিগুলিতে ফাইলের নাম উল্লেখ করতে যাচ্ছেন, চুক্তি কী? যে বিএস এর জন্য যে কেউ পড়েন তা মন বগল। " এমনকি জেমস কানজের মতো বিশেষজ্ঞরাও যে রপ্তানিটি আসলে এই জাতীয় তা মানতে অসুবিধা হয় " "কি? !!!!
কৌতূহলী

34

যদিও স্ট্যান্ডার্ড সি ++ এর কোনও প্রয়োজন নেই, কিছু সংকলকগুলির প্রয়োজন যে সমস্ত ফাংশন এবং শ্রেণি টেম্পলেটগুলি ব্যবহৃত হয় সেগুলি প্রতিটি অনুবাদ ইউনিটে উপলব্ধ করা দরকার। বাস্তবে, এই সংকলকগুলির জন্য, টেমপ্লেট ফাংশনগুলির বডিগুলি অবশ্যই একটি শিরোনাম ফাইলটিতে উপলব্ধ করতে হবে। পুনরাবৃত্তি করার: এর অর্থ এই যে সংকলকগুলি তাদের নন-শিরোনামযুক্ত ফাইলগুলিতে যেমন .cpp ফাইলগুলিতে সংজ্ঞায়িত হতে দেয় না

এখানে একটি রফতানি কীওয়ার্ড রয়েছে যা এই সমস্যাটি প্রশমিত করার কথা, তবে এটি পোর্টেবল হওয়ার কাছাকাছি কোথাও নেই।


আমি কেন তাদের "ইনলাইন" মূলশব্দ দিয়ে .cpp ফাইলে প্রয়োগ করতে পারি না?
মেনিড

2
আপনি পারেন, এবং আপনাকে "ইনলাইন" এমনকি রাখতে হবে না। তবে আপনি সেগুলি কেবল সেই সিপিপি ফাইলে এবং অন্য কোথাও ব্যবহার করতে সক্ষম হবেন।
ভাভা

10
এটি প্রায় সর্বাধিক নির্ভুল উত্তর, "এর অর্থ এই যে সংকলকগুলি তাদের নন-শিরোনামযুক্ত ফাইলে যেমন .cpp ফাইলগুলিতে সংজ্ঞায়িত করতে দেয় না" তা স্পষ্টতই মিথ্যা।
অরবিটে লাইটনেস রেস

28

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

মূলশব্দটির সাথে একটি বৈশিষ্ট্য exportছিল যা পৃথক সংকলনের জন্য ব্যবহার করা হয়েছিল। exportবৈশিষ্ট্য অবচিত C++11এবং, আমি যতদূর জানি, শুধুমাত্র এক কম্পাইলার বাস্তবায়ন। আপনার ব্যবহার করা উচিত নয় export। পৃথক সংকলন সম্ভব নয় C++বা C++11কিন্তু হয়তো মধ্যেC++17 , যদি ধারণাগুলি এটিকে তৈরি করে, আমাদের পৃথক সংকলনের কিছু উপায় থাকতে পারে।

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

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


15

এর অর্থ এই যে টেমপ্লেট শ্রেণীর পদ্ধতি প্রয়োগের সংজ্ঞা দেওয়ার সবচেয়ে বহনযোগ্য উপায় হ'ল টেমপ্লেট শ্রেণীর সংজ্ঞায়নের মধ্যে তাদের সংজ্ঞা দেওয়া।

template < typename ... >
class MyClass
{

    int myMethod()
    {
       // Not just declaration. Add method implementation here
    }
};

15

যদিও উপরে অনেকগুলি ভাল ব্যাখ্যা রয়েছে, তবুও আমি টেমপ্লেটগুলি শিরোনাম এবং শরীরে পৃথক করার একটি ব্যবহারিক উপায় অনুপস্থিত।
আমার প্রধান উদ্বেগ হ'ল সমস্ত টেম্পলেট ব্যবহারকারীদের পুনরায় সংকলন এড়ানো, যখন আমি এর সংজ্ঞা পরিবর্তন করি।
টেমপ্লেট বডিতে সমস্ত টেম্পলেট ইনস্ট্যান্টেশন থাকা আমার পক্ষে একটি কার্যকর সমাধান নয়, যেহেতু টেমপ্লেট লেখক তার ব্যবহার এবং টেমপ্লেট ব্যবহারকারীর এটিকে সংশোধন করার অধিকার নাও থাকতে পারে তা সমস্তই জানেন না।
আমি নিম্নলিখিত পদ্ধতিটি গ্রহণ করেছি, যা পুরানো সংকলকগুলির জন্যও কাজ করে (জিসিসি ৪.৩.৪, এসিসি এ .০৩.১৩)।

প্রতিটি টেম্পলেট ব্যবহারের জন্য নিজস্ব শিরোনাম ফাইলে একটি টাইপিডেফ রয়েছে (ইউএমএল মডেল থেকে উত্পন্ন)। এর শরীরে ইনস্ট্যান্টেশন রয়েছে (যা একটি লাইব্রেরিতে শেষ হয় যা শেষের সাথে সংযুক্ত থাকে)।
টেমপ্লেটের প্রতিটি ব্যবহারকারীর সেই শিরোনাম ফাইল অন্তর্ভুক্ত করে এবং টাইপিডেফ ব্যবহার করে।

একটি পরিকল্পিত উদাহরণ:

MyTemplate.h:

#ifndef MyTemplate_h
#define MyTemplate_h 1

template <class T>
class MyTemplate
{
public:
  MyTemplate(const T& rt);
  void dump();
  T t;
};

#endif

MyTemplate.cpp:

#include "MyTemplate.h"
#include <iostream>

template <class T>
MyTemplate<T>::MyTemplate(const T& rt)
: t(rt)
{
}

template <class T>
void MyTemplate<T>::dump()
{
  cerr << t << endl;
}

MyInstantiatedTemplate.h:

#ifndef MyInstantiatedTemplate_h
#define MyInstantiatedTemplate_h 1
#include "MyTemplate.h"

typedef MyTemplate< int > MyInstantiatedTemplate;

#endif

MyInstantiatedTemplate.cpp:

#include "MyTemplate.cpp"

template class MyTemplate< int >;

main.cpp:

#include "MyInstantiatedTemplate.h"

int main()
{
  MyInstantiatedTemplate m(100);
  m.dump();
  return 0;
}

এইভাবে কেবলমাত্র টেম্পলেট ইনস্ট্যান্টেশনগুলি পুনরায় সংযুক্ত করা দরকার, সমস্ত টেম্পলেট ব্যবহারকারী (এবং নির্ভরতা) নয়।


1
MyInstantiatedTemplate.hফাইল এবং যুক্ত MyInstantiatedTemplateপ্রকারের ব্যতিক্রমগুলি সহ আমি এই পদ্ধতির পছন্দ করি । আপনি যদি এটি ব্যবহার না করেন তবে এটি একটু ক্লিনার im : একটি ভিন্ন প্রশ্নে আমার উত্তর এই দেখাচ্ছে চেকআউট stackoverflow.com/a/41292751/4612476
ক্যামেরন Tacklind

এটি দুটি বিশ্বের সেরা নেয়। আমি এই উত্তরটি উচ্চতর রেট দেওয়া চাই! একই ধারণাটির কিছুটা পরিচ্ছন্ন বাস্তবায়নের জন্য উপরের লিঙ্কটিও দেখুন।
কৃষক

8

এখানে এখানে উল্লেখযোগ্য কিছু যুক্ত করতে। টেম্পলেটগুলি ফাংশন না করে যখন কেউ কার্যকর পদ্ধতিতে টেম্পলেট শ্রেণীর পদ্ধতিগুলি নির্ধারণ করতে পারে।


myQueue.hpp:

template <class T> 
class QueueA {
    int size;
    ...
public:
    template <class T> T dequeue() {
       // implementation here
    }

    bool isEmpty();

    ...
}    

myQueue.cpp:

// implementation of regular methods goes like this:
template <class T> bool QueueA<T>::isEmpty() {
    return this->size == 0;
}


main()
{
    QueueA<char> Q;

    ...
}

2
সত্যিকারের মানুষের জন্য ??? যদি এটি সত্য হয় তবে আপনার উত্তরটি যথাযথ হিসাবে পরীক্ষা করা উচিত anyone আপনি যদি কেবল .cpp এ টেমপ্লেট সদস্যের সদস্যগুলি সংজ্ঞায়িত করতে পারেন তবে কারও কাছে এই সমস্ত হ্যাকি ভোডো স্টাফের দরকার নেই কেন?
মাইকেল চতুর্থ

ভাল এটি কাজ করে না MS এমএসভিসি 2019-তে কমপক্ষে, টেমপ্লেট শ্রেণীর সদস্য ফাংশনের জন্য অমীমাংসিত বাহ্যিক প্রতীক পেয়ে।
মাইকেল চতুর্থ

আমার কাছে পরীক্ষার জন্য এমএসভিসি 2019 নেই। এটি সি ++ স্ট্যান্ডার্ড দ্বারা অনুমোদিত। এখন, এমএসভিসি সর্বদা নিয়ম মেনে চলা না করার জন্য কুখ্যাত। যদি আপনি ইতিমধ্যে না পেয়ে থাকেন তবে প্রকল্প সেটিংস -> সি / সি ++ -> ভাষা -> কনফারেন্স মোড -> হ্যাঁ (অনুমতিপ্রাপ্ত) চেষ্টা করুন।
নিকোস

1
এই সঠিক উদাহরণটি কাজ করে তবে তারপরে আপনি isEmptyঅন্য কোনও অনুবাদ ইউনিট থেকে কল করতে পারবেন না myQueue.cpp...
এমএম

7

উদ্বেগটি হ'ল অতিরিক্ত সংকলন সময় এবং বাইনারি আকারের ফোলাটি এটি ব্যবহার করে সমস্ত .cpp মডিউলগুলির অংশ হিসাবে .H সংকলন করে উত্পাদিত হয়, অনেক ক্ষেত্রে আপনি যা করতে পারেন তা হ'ল টেম্পলেট শ্রেণিটি একটি অ-টেমপ্ল্লেটেড বেস শ্রেণীর থেকে নামিয়ে আনতে হবে ইন্টারফেসের নন-নির্ভর-নির্ভর অংশ, এবং সেই বেস শ্রেণীর .cpp ফাইলে এর প্রয়োগ থাকতে পারে।


2
এই প্রতিক্রিয়াটি আরও বেশ মোডেড করা উচিত। আমি " স্বাধীনভাবে " আপনার একই পন্থাটি আবিষ্কার করেছি এবং এটি ইতিমধ্যে ব্যবহার করার জন্য অন্য কারও জন্য বিশেষভাবে সন্ধান করছিলাম, যেহেতু আমি কৌতূহল বোধ করি এটি যদি অফিসিয়াল ধরণ এবং এটির কোনও নাম পাওয়া যায় কিনা। আমার দৃষ্টিভঙ্গি হ'ল class XBaseযেখানেই একটি প্রয়োগ করতে হবে সেখানেই template class Xটাইপ-নির্ভর অংশগুলিকে Xরেখে বাকি সবগুলিকেই প্রয়োগ করা XBase
ফ্যাবিও এ

6

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


5
"শিরোনামের ফাইলগুলি সংকলিত হয় না" - এটি বর্ণনা করার পক্ষে এটি একটি সত্যই অভিনব উপায়। শিরোনাম ফাইলগুলি "সি / সিপিপি" ফাইলের মতো অনুবাদ ইউনিটের অংশ হতে পারে।
ফ্লেক্সো

2
প্রকৃতপক্ষে, এটি প্রায় সত্যের বিপরীত, যা শিরোনাম ফাইলগুলি প্রায়শই অনেক বার সংকলিত হয়, যেখানে উত্স ফাইলটি সাধারণত একবার সংকলিত হয়।
xaxxon

6

সংকলনের পদক্ষেপের সময় আপনি যখন কোনও টেমপ্লেট ব্যবহার করেন তখন সংকলক প্রতিটি টেম্পলেট ইনস্ট্যান্টেশনের জন্য কোড তৈরি করবে। সংকলন এবং লিঙ্কিংয়ের প্রক্রিয়াতে .cpp ফাইলগুলিকে খাঁটি অবজেক্ট বা মেশিন কোডে রূপান্তর করা হয় যার মধ্যে উল্লেখগুলি বা অপরিজ্ঞাত চিহ্ন রয়েছে কারণ আপনার মেইন.সিপিপি অন্তর্ভুক্ত .h ফাইলগুলির কোনও বাস্তবায়ন YET নেই। এগুলি অন্য কোনও অবজেক্ট ফাইলের সাথে সংযুক্ত হওয়ার জন্য প্রস্তুত যা আপনার টেম্পলেটটির জন্য একটি বাস্তবায়ন সংজ্ঞায়িত করে এবং এর ফলে আপনার একটি সম্পূর্ণ আউটআউট এক্সিকিউটেবল থাকে।

তবে যেহেতু আপনি সংজ্ঞায়িত প্রতিটি টেমপ্লেট ইনস্ট্যান্টেশনগুলির জন্য কোড তৈরি করতে টেমপ্লেটগুলি সংকলন পদক্ষেপে প্রক্রিয়া করা প্রয়োজন, তাই কেবলমাত্র শিরোনাম ফাইল থেকে পৃথক একটি টেম্পলেট সংকলন কাজ করবে না কারণ তারা সর্বদা হাত এবং হাত দিয়ে চলে যায়, খুব কারণেই প্রতিটি টেম্পলেট ইনস্ট্যান্টেশন পুরোপুরি আক্ষরিক অর্থে একটি সম্পূর্ণ নতুন বর্গ। একটি নিয়মিত শ্রেণিতে আপনি .h এবং .cpp পৃথক করতে পারেন কারণ .h সেই শ্রেণীর একটি নীলনকশা এবং .cpp হ'ল কাঁচা বাস্তবায়ন তাই যে কোনও বাস্তবায়ন ফাইলগুলি নিয়মিত সংকলন এবং সংযুক্ত করা যায়, তবে টেমপ্লেটগুলি ব্যবহার করে .এইচ কীভাবে একটি নীলনকশা শ্রেণীর দেখতে হবে না কীভাবে বস্তুটিকে কোনও টেমপ্লেট অর্থ বোঝানো উচিত। সিপিপি ফাইল কোনও শ্রেণীর কাঁচা নিয়মিত প্রয়োগ নয়, এটি কেবল একটি শ্রেণীর জন্য একটি নীলনকশা, তাই। টেমপ্লেট ফাইলটির কোনও প্রয়োগ '

অতএব টেমপ্লেটগুলি কখনই পৃথকভাবে সংকলিত হয় না এবং কেবল যেখানেই আপনার অন্য কোনও উত্স ফাইলে একটি কংক্রিট ইনস্ট্যান্টেশন রয়েছে সেখানেই সংকলন করা হয়। যাইহোক, কংক্রিট ইনস্ট্যান্টেশন টেমপ্লেট ফাইলটির বাস্তবায়ন জানতে হবে, কারণ কেবলমাত্র পরিবর্তনটিtypename T.h ফাইলে একটি কংক্রিট টাইপ ব্যবহার করা কাজটি করছে না কারণ .cpp লিঙ্ক করার জন্য কী আছে, আমি এটি পরে খুঁজে পাচ্ছি না কারণ মনে রাখবেন টেমপ্লেটগুলি বিমূর্ত এবং সংকলন করা যায় না, তাই আমাকে বাধ্য করা হয়েছে বাস্তবায়ন এখনই দিতে যাতে আমি কী সংকলন এবং লিঙ্ক করতে জানি, এবং এখন আমার কাছে বাস্তবায়ন আছে এটি বদ্ধ সোর্স ফাইলের সাথে সংযুক্ত হয়ে যায়। মূলত, আমি যখন একটি টেমপ্লেট ইনস্ট্যান্ট করি তার মুহূর্তে আমার একটি সম্পূর্ণ নতুন ক্লাস তৈরি করা দরকার এবং আমি এটি করতে পারি না যদি আমি জানতাম না যে আমি যে ধরণের প্রকারটি সরবরাহ করি তা ব্যবহার করার সময় কীভাবে দেখতে হবে যদি না আমি সংকলককে বিজ্ঞপ্তি না করি টেমপ্লেট বাস্তবায়ন, সুতরাং এখন সংকলকটি Tআমার ধরণের সাথে প্রতিস্থাপন করতে পারে এবং একটি কংক্রিট শ্রেণি তৈরি করতে পারে যা সংকলন এবং লিঙ্কে প্রস্তুত।

সংক্ষিপ্তসার হিসাবে, টেমপ্লেটগুলি ক্লাসগুলি কেমন দেখতে হবে তার জন্য ব্লুপ্রিন্টগুলি হয়, কোনও বস্তুর কীভাবে দেখতে হবে তা ক্লাসগুলি ব্লুপ্রিন্ট are আমি টেমপ্লেটগুলিকে তাদের কংক্রিট ইনস্ট্যান্টেশন থেকে পৃথক করে সংকলন করতে পারি না কারণ সংকলকটি কেবলমাত্র কংক্রিটের প্রকারগুলি সংকলন করে, অন্য কথায়, কমপক্ষে সি ++ তে টেমপ্লেটগুলি খাঁটি ভাষার বিমূর্ততা। আমাদের কথা বলতে গেলে এটি অ্যাবস্ট্রাক্ট টেমপ্লেটগুলি ডি-অ্যাবস্ট্রাক্ট করতে হবে এবং এটি মোকাবেলায় একটি কংক্রিট ধরণের মাধ্যমে আমরা তা করি যাতে আমাদের টেমপ্লেট বিমূর্তিটি একটি নিয়মিত শ্রেণীর ফাইলে রূপান্তরিত হতে পারে এবং পরিবর্তে, এটি সাধারণত সংকলন করা যায়। টেমপ্লেট। এইচ ফাইল এবং টেমপ্লেট। সিপিপি ফাইল পৃথক করা অর্থহীন। এটি অযৌক্তিক কারণ কারণ .cpp এবং .h এর পৃথকীকরণ কেবল তখনই হয় যেখানে .cpp পৃথকভাবে সংকলন করা যায় এবং টেমপ্লেটগুলির সাথে পৃথকভাবে সংযুক্ত করা যায় যেহেতু আমরা সেগুলি পৃথকভাবে সংকলন করতে পারি না, কারণ টেমপ্লেটগুলি বিমূর্ততা,

typename Tসংকলনের পদক্ষেপের সময় এর অর্থ প্রতিস্থাপনের সাথে লিঙ্কিং স্টেপ নয়, তাই যদি আমি Tকোনও কংক্রিট মান ধরণের হিসাবে পরিবর্তিত না হয়ে কোনও টেম্পলেট সংকলনের চেষ্টা করি যা সংকলকের সম্পূর্ণ অর্থহীন এবং ফলস্বরূপ অবজেক্ট কোড তৈরি করা যায় না কারণ এটি হয় না কি জানি T

প্রযুক্তিগতভাবে এমন কোনও ধরণের কার্যকারিতা তৈরি করা সম্ভব যা টেমপ্লেট। সিপিপি ফাইলটি সংরক্ষণ করবে এবং প্রকারগুলি যখন অন্য উত্সগুলিতে এটি সন্ধান করবে তখন আমি মনে করি যে স্ট্যান্ডার্ডের এমন একটি কীওয়ার্ড রয়েছে exportযা আপনাকে আলাদাভাবে টেমপ্লেট রাখার অনুমতি দেবে সিপিপি ফাইল কিন্তু অনেক সংকলক আসলে এটি প্রয়োগ করে না।

কেবলমাত্র একটি পার্শ্ব নোট, কোনও টেম্পলেট শ্রেণীর জন্য বিশেষীকরণ করার সময় আপনি শিরোনামটি বাস্তবায়ন থেকে আলাদা করতে পারেন কারণ সংজ্ঞা অনুসারে বিশেষীকরণের অর্থ হ'ল আমি একটি কংক্রিটের জন্য বিশেষীকরণ করছি যা পৃথকভাবে সংকলন এবং সংযুক্ত করা যেতে পারে।


4

পৃথক বাস্তবায়ন করার একটি উপায় নিম্নরূপ:

//inner_foo.h

template <typename T>
struct Foo
{
    void doSomething(T param);
};


//foo.tpp
#include "inner_foo.h"
template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}


//foo.h
#include <foo.tpp>

//main.cpp
#include <foo.h>

অভ্যন্তরীণ_ফুতে এগিয়ে ঘোষণা রয়েছে decla foo.tpp এর প্রয়োগ রয়েছে এবং এতে অন্তর্_ফু। foo.tpp অন্তর্ভুক্ত করতে এবং foo.h এর একটি মাত্র লাইন থাকবে।

সংকলনের সময়, foo.h এর সামগ্রীগুলি foo.tpp এ অনুলিপি করা হয় এবং তারপরে সম্পূর্ণ ফাইলটি foo.h এ অনুলিপি করা হয় যার পরে এটি সংকলিত হয়। এইভাবে, কোনও অতিরিক্ত ফাইলের বিনিময়ে কোনও সীমাবদ্ধতা নেই এবং নামকরণটি সামঞ্জস্যপূর্ণ।

আমি এটি করছি কারণ কোড বিরতির স্থির বিশ্লেষকরা যখন এটি * .tpp এ ক্লাসের অগ্রণী ঘোষণাগুলি দেখতে না পান। কোনও আইডিইতে কোড লেখার সময় বা YouCompleteMe বা অন্যদের ব্যবহার করার সময় এটি বিরক্তিকর।


2
এস / ইনার_ফু / ফু / জি এবং foo.h. এর শেষে foo.tpp অন্তর্ভুক্ত করে একটি কম ফাইল।

1

আমি এই জিসিসি পৃষ্ঠাটি দেখার পরামর্শ দিচ্ছি যা টেমপ্লেট ইনস্ট্যান্টেশনের জন্য "সিফ্রন্ট" এবং "বোরল্যান্ড" মডেলের মধ্যে ট্রেডঅফগুলি নিয়ে আলোচনা করে।

https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Template-Instantiation.html

"বোরল্যান্ড" মডেলটি লেখকের পরামর্শের সাথে মিলে যায়, পুরো টেম্পলেট সংজ্ঞা প্রদান করে এবং একাধিকবার জিনিস সংকলিত করে।

এটিতে ম্যানুয়াল এবং স্বয়ংক্রিয় টেম্পলেট ইনস্ট্যান্টেশন ব্যবহার সম্পর্কিত স্পষ্ট প্রস্তাবনা রয়েছে। উদাহরণস্বরূপ, "-repo" বিকল্পটি টেমপ্লেট সংগ্রহ করতে ব্যবহার করা যেতে পারে যা তাত্ক্ষণিক হওয়া দরকার। বা অন্য বিকল্প হ'ল ম্যানুয়াল টেম্পলেট ইনস্ট্যান্টেশন জোর করতে "-fno-implic-templates" ব্যবহার করে স্বয়ংক্রিয় টেম্পলেট ইনস্ট্যান্টেশনগুলি অক্ষম করা।

আমার অভিজ্ঞতায় আমি প্রতিটি সংকলনের ইউনিট (টেমপ্লেট লাইব্রেরি ব্যবহার করে) জন্য সি ++ স্ট্যান্ডার্ড লাইব্রেরি এবং বুস্ট টেম্পলেটগুলির উপর নির্ভর করি। আমার বড় টেম্পলেট ক্লাসের জন্য, আমি আমার প্রয়োজনীয় ধরণের জন্য ম্যানুয়াল টেমপ্লেট ইনস্ট্যান্টেশন করি।

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

আমি যদি সত্যিই গতি সম্পর্কে উদ্বিগ্ন ছিলাম, আমি মনে করি আমি প্রম্পম্পাইল্ড শিরোনাম https://gcc.gnu.org/onlinesocs/gcc/Precompiled-Heedia.html ব্যবহার করে অন্বেষণ করব

যা অনেক সংকলকের সমর্থন পাচ্ছে। তবে আমি মনে করি টেমপ্লেট শিরোনাম ফাইলগুলির সাথে প্রাকম্পম্পাইল্ড শিরোনামগুলি কঠিন হবে।


-2

হেডার ফাইলগুলিতে ঘোষণা এবং সংজ্ঞা উভয়ই লিখাই ভাল ধারণা হ'ল পাঠযোগ্যতার জন্য। ধরুন ইউটিলিটি.-তে এরকম একটি টেম্পলেট ফাংশন রয়েছে:

template <class T>
T min(T const& one, T const& theOther);

এবং ইউটিলিটি.সি.পি. তে:

#include "Utility.h"
template <class T>
T min(T const& one, T const& other)
{
    return one < other ? one : other;
}

অপারেটর (<) এর চেয়ে কম প্রয়োগ করতে এখানে প্রতিটি টি ক্লাসের প্রয়োজন। আপনি "<" প্রয়োগ না করে এমন দুটি শ্রেণীর উদাহরণের তুলনা করলে এটি একটি সংকলক ত্রুটি ফেলবে।

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


-7

আপনি আসলে .cpp ফাইলের পরিবর্তে একটি টেম্পলেট ফাইলের মধ্যে আপনার টেম্পলেট শ্রেণীর সংজ্ঞা দিতে পারেন। যে কেউ বলছেন আপনি কেবল একটি শিরোলেখ ফাইলের মধ্যে এটি সংজ্ঞায়িত করতে পারেন তা ভুল। এটি এমন কিছু যা সি ++ 98 এর সমস্ত পথে কাজ করে।

আপনার সংকলকটি আপনার .templet ফাইলটিকে সি ++ ফাইল হিসাবে বিবেচনা করতে ইন্টেলি অর্থে রাখতে ভুলবেন না।

গতিশীল অ্যারে শ্রেণীর জন্য এটির উদাহরণ এখানে।

#ifndef dynarray_h
#define dynarray_h

#include <iostream>

template <class T>
class DynArray{
    int capacity_;
    int size_;
    T* data;
public:
    explicit DynArray(int size = 0, int capacity=2);
    DynArray(const DynArray& d1);
    ~DynArray();
    T& operator[]( const int index);
    void operator=(const DynArray<T>& d1);
    int size();

    int capacity();
    void clear();

    void push_back(int n);

    void pop_back();
    T& at(const int n);
    T& back();
    T& front();
};

#include "dynarray.template" // this is how you get the header file

#endif

এখন আপনার .template ফাইলের মধ্যে আপনি নিজের ফাংশনগুলি সংজ্ঞায়িত করেন ঠিক কীভাবে আপনি সাধারণত করেন।

template <class T>
DynArray<T>::DynArray(int size, int capacity){
    if (capacity >= size){
        this->size_ = size;
        this->capacity_ = capacity;
        data = new T[capacity];
    }
    //    for (int i = 0; i < size; ++i) {
    //        data[i] = 0;
    //    }
}

template <class T>
DynArray<T>::DynArray(const DynArray& d1){
    //clear();
    //delete [] data;
    std::cout << "copy" << std::endl;
    this->size_ = d1.size_;
    this->capacity_ = d1.capacity_;
    data = new T[capacity()];
    for(int i = 0; i < size(); ++i){
        data[i] = d1.data[i];
    }
}

template <class T>
DynArray<T>::~DynArray(){
    delete [] data;
}

template <class T>
T& DynArray<T>::operator[]( const int index){
    return at(index);
}

template <class T>
void DynArray<T>::operator=(const DynArray<T>& d1){
    if (this->size() > 0) {
        clear();
    }
    std::cout << "assign" << std::endl;
    this->size_ = d1.size_;
    this->capacity_ = d1.capacity_;
    data = new T[capacity()];
    for(int i = 0; i < size(); ++i){
        data[i] = d1.data[i];
    }

    //delete [] d1.data;
}

template <class T>
int DynArray<T>::size(){
    return size_;
}

template <class T>
int DynArray<T>::capacity(){
    return capacity_;
}

template <class T>
void DynArray<T>::clear(){
    for( int i = 0; i < size(); ++i){
        data[i] = 0;
    }
    size_ = 0;
    capacity_ = 2;
}

template <class T>
void DynArray<T>::push_back(int n){
    if (size() >= capacity()) {
        std::cout << "grow" << std::endl;
        //redo the array
        T* copy = new T[capacity_ + 40];
        for (int i = 0; i < size(); ++i) {
            copy[i] = data[i];
        }

        delete [] data;
        data = new T[ capacity_ * 2];
        for (int i = 0; i < capacity() * 2; ++i) {
            data[i] = copy[i];
        }
        delete [] copy;
        capacity_ *= 2;
    }
    data[size()] = n;
    ++size_;
}

template <class T>
void DynArray<T>::pop_back(){
    data[size()-1] = 0;
    --size_;
}

template <class T>
T& DynArray<T>::at(const int n){
    if (n >= size()) {
        throw std::runtime_error("invalid index");
    }
    return data[n];
}

template <class T>
T& DynArray<T>::back(){
    if (size() == 0) {
        throw std::runtime_error("vector is empty");
    }
    return data[size()-1];
}

template <class T>
T& DynArray<T>::front(){
    if (size() == 0) {
        throw std::runtime_error("vector is empty");
    }
    return data[0];
    }

2
বেশিরভাগ লোকেরা শিরোনাম ফাইলটিকে এমন কোনও কিছু হিসাবে সংজ্ঞায়িত করবে যা উত্স ফাইলগুলিতে সংজ্ঞা প্রচার করে। সুতরাং আপনি হয়ত ".template" ফাইল এক্সটেনশনটি ব্যবহার করার সিদ্ধান্ত নিয়েছেন তবে আপনি একটি শিরোনাম ফাইল লিখেছেন।
টমি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.