একটি .CPP ফাইলে সি ++ টেম্পলেট ফাংশন সংজ্ঞা সংরক্ষণ করে


526

আমার কিছু টেম্পলেট কোড রয়েছে যা আমি শিরোনামের ইনলাইন পরিবর্তে সিপিপি ফাইলে সংরক্ষণ করতে পছন্দ করব। আমি জানি যতক্ষণ না আপনি জানেন যে কোন টেম্পলেট ধরণের ব্যবহৃত হবে। উদাহরণ স্বরূপ:

.h ফাইল

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

.cpp ফাইল

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

শেষ দুটি লাইন নোট করুন - foo :: do টেম্পলেট ফাংশনটি কেবল ints এবং std :: স্ট্রিংয়ের সাথেই ব্যবহৃত হয়, সুতরাং এই সংজ্ঞাটির অর্থ অ্যাপটি লিঙ্ক করবে।

আমার প্রশ্নটি হ'ল - এটি কি কদর্য হ্যাক নাকি এটি অন্যান্য সংকলক / লিকারগুলি নিয়ে কাজ করবে? আমি এই মুহুর্তে কেবলমাত্র ভিএস ২০০৮ এর সাথে এই কোডটি ব্যবহার করছি তবে অন্য পরিবেশে পোর্ট করতে চাইব।


22
এটি সম্ভব ছিল আমার কোনও ধারণা ছিল না - একটি আকর্ষণীয় কৌশল! এটি জানার জন্য সাম্প্রতিক কিছু কাজকে সাহায্য করতে পারে - চিয়ার্স!
xan

69
আমাকে যে জিনিসটি স্টম্পস করে তা হ'ল doশনাক্তকারী হিসাবে ব্যবহার করা: পি
কোয়ান্টিন

আমি জিসিসির সাথে অনুরূপ কিছু করেছি, তবে এখনও গবেষণা করছি
নিক

16
এটি কোনও "হ্যাক" নয়, এটি এগিয়ে ঘোষণা is ভাষার স্ট্যান্ডার্ডে এটির একটি জায়গা রয়েছে; সুতরাং হ্যাঁ, এটি প্রতিটি স্ট্যান্ডার্ড কনফর্মেন্ট সংকলকটিতে অনুমোদিত।
আহমেট ইপকিন 14

1
যদি আপনার কয়েক ডজন পদ্ধতি থাকে? আপনি কি template class foo<int>;template class foo<std::string>;.cpp ফাইলের শেষে করতে পারেন ?
অজানা

উত্তর:


231

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

আমি সি ++ এফএকিউ লাইট থেকে নিম্নলিখিত বিষয়গুলি পড়ার পরামর্শ দিচ্ছি :

এগুলি (এবং অন্যান্য) টেম্পলেট সংক্রান্ত সমস্যাগুলি সম্পর্কে তারা প্রচুর বিশদে যায়।


39
কেবলমাত্র উত্তরটির পরিপূরক হিসাবে, রেফারেন্সযুক্ত লিঙ্কটি প্রশ্নটিকে ইতিবাচকভাবে উত্তর দেয়, অর্থাত রব যে পরামর্শ দিয়েছে তা করা এবং কোড বহনযোগ্য হতে পারে এটি করা সম্ভব।
আইভোট্রন

159
আপনি কি কেবল উত্তরটিতে প্রাসঙ্গিক অংশগুলি পোস্ট করতে পারেন? এমনকি কেন এই জাতীয় রেফারেন্সিং অনুমোদিত। এই লিঙ্কটিতে কী কী সন্ধান করতে হবে সে সম্পর্কে আমার কোনও ধারণা নেই কারণ এটি তখন থেকেই ভারী পরিবর্তন হয়েছে।
Ident

124

সুস্পষ্ট টেম্পলেট বিশেষায়নের (বা কমপক্ষে VS2008 এ) সঠিক সিনট্যাক্সটি কী (আমি যেমন করেছি) এর জন্য এই পৃষ্ঠার অন্যদের জন্য এটি নীচে ...

আপনার .h ফাইলে ...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

এবং আপনার .cpp ফাইল এ

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

15
আপনার অর্থ কি "স্পষ্টত CLASS টেম্পলেট বিশেষায়নের জন্য"? সেক্ষেত্রে সেই টেম্প্লেটেড ক্লাসের প্রতিটি ফাংশন কভার করবে?
আর্থার

@ আর্থার মনে হয় না, আমার কিছু টেম্পলেট পদ্ধতি শিরোনামে থাকে এবং সিপিপিতে বেশিরভাগ অন্যান্য পদ্ধতি রয়েছে, ভাল কাজ করে। খুব সুন্দর সমাধান।
user1633272

প্রশ্নকারীর ক্ষেত্রে, তাদের কোনও ফাংশন টেম্পলেট রয়েছে, শ্রেণির টেম্পলেট নয়।
ব্যবহারকারী 253751

23

এই কোডটি সুগঠিত। আপনাকে কেবল মনোযোগ দিতে হবে যে টেম্পলেটটির সংজ্ঞাটি ইনস্ট্যান্টেশনের পর্যায়ে দৃশ্যমান। মানটির উদ্ধৃতি দিতে, § 14.7.2.4:

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


2
কী অ রপ্তানি মানে?
ড্যান নিসেনবাউম

1
@ ড্যান দৃশ্যমান এটির সংকলনের ইউনিটের ভিতরে কেবল এটির বাইরে নয়। আপনি যদি একাধিক সংকলন ইউনিটকে একসাথে লিঙ্ক করেন তবে রফতানি চিহ্নগুলি তাদের জুড়ে ব্যবহার করা যেতে পারে (এবং টেমপ্লেটগুলির ক্ষেত্রে একটির একটি বা কমপক্ষে অবশ্যই থাকতে হবে, ধারাবাহিক সংজ্ঞা থাকতে পারে অন্যথায় আপনি ইউবিতে চলে যান)।
কনরাড রুডলফ

ধন্যবাদ। আমি ভেবেছিলাম যে সমস্ত ফাংশন (ডিফল্টরূপে) সংকলনের ইউনিটের বাইরে দৃশ্যমান। আমার যদি দুটি সংকলন ইউনিট a.cpp(ফাংশন সংজ্ঞায়িত করা a() {}) এবং b.cpp(ফাংশনটি সংজ্ঞায়িত করা b() { a() }) থাকে তবে এটি সফলভাবে লিঙ্ক করবে। আমি যদি ঠিকই বলে থাকি তবে উপরের উক্তিটি সাধারণ মামলার জন্য প্রয়োগ করবে না বলে মনে হচ্ছে ... আমি কি কোথাও ভুল করছি?
ড্যান নিসেনবাউম

@ ডান তুচ্ছ কাউন্টারেক্সেক্সেল: inlineফাংশন
কনরাড রুডলফ

1
@ ড্যান ফাংশন টেম্পলেটগুলি অন্তর্নিহিত inline। কারণটি হ'ল মানকযুক্ত সি ++ এবিআই ব্যতীত অন্যথায় এর প্রভাব কী তা নির্ধারণ করা শক্ত / অসম্ভব।
কনরাড রুডলফ

15

টেমপ্লেটগুলি সমর্থিত যেখানেই এটি কাজ করা উচিত। সুস্পষ্ট টেম্পলেট ইনস্ট্যান্টেশন হল সি ++ স্ট্যান্ডার্ডের একটি অংশ।


13

আপনার উদাহরণটি সঠিক তবে খুব বহনযোগ্য নয়। কিছুটা ক্লিনার সিনট্যাক্সও ব্যবহার করা যেতে পারে (@ নেমস্পেস-সিড দ্বারা চিহ্নিত হিসাবে)।

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

আপনার কাছে যা আছে তার একটি বিকল্প পদ্ধতির সামান্য প্রকরণ: একটি তৃতীয় ফাইল যুক্ত করুন যা টেম্পলেট বাস্তবায়ন / ইনস্ট্যান্টেশন ফাইল।

foo.h ফাইল

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

foo.cpp ফাইল

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp ফাইল

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

একটি সতর্কতামূলক হ'ল আপনাকে পরবর্তী সংকলন করার foo-impl.cppপরিবর্তে foo.cppসংকলকটি সংকলন করতে বলা দরকার যা কিছু না করে।

অবশ্যই, তৃতীয় ফাইলটিতে আপনার একাধিক বাস্তবায়ন থাকতে পারে বা আপনি ব্যবহার করতে চান এমন প্রতিটি ধরণের জন্য একাধিক বাস্তবায়ন ফাইল থাকতে পারে।

অন্যান্য ব্যবহারের জন্য টেম্প্লেড ক্লাস ভাগ করে নেওয়ার সময় এটি আরও অনেক নমনীয়তা সক্ষম করে।

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


এটি আপনাকে কী কিনে দেয়? একটি নতুন বিশেষীকরণ যুক্ত করতে আপনার এখনও foo-impl.cpp সম্পাদনা করতে হবে।
এমকে

বাস্তবায়নের বিশদটি পৃথককরণ (উরফ সংজ্ঞাগুলি এতে foo.cpp) যা থেকে সংস্করণগুলি আসলে সংকলিত (ইন foo-impl.cpp) এবং ঘোষণাপত্র (ইন foo.h) in আমি পছন্দ করি না যে বেশিরভাগ সি ++ টেম্পলেটগুলি পুরো শিরোনাম ফাইলগুলিতে সংজ্ঞায়িত হয়। এটি c[pp]/hপ্রতিটি শ্রেণি / নেমস্পেস / যাই হোক না কেন গ্রুপিংয়ের জন্য জুড়ির সি / সি ++ স্ট্যান্ডার্ডের বিপরীতে । লোকেরা এখনও একচেটিয়া শিরোলেখ ফাইলগুলি কেবলমাত্র এই বিকল্পটি ব্যাপকভাবে ব্যবহৃত বা পরিচিত না বলে ব্যবহার করে বলে মনে হচ্ছে।
ক্যামেরন ট্যাকলিন্ড

1
@MK। আমি প্রথমে উত্স ফাইলটিতে সংজ্ঞাটির শেষে স্পষ্ট টেম্পলেট ইনস্ট্যান্টেশনগুলি রেখেছিলাম যতক্ষণ না আমার অন্য কোথাও আরও ইনস্ট্যান্টেশন প্রয়োজন (উদাহরণস্বরূপ ইউনিট টেস্টগুলি টমলেটযুক্ত প্রকার হিসাবে ব্যবহার করে)। এই বিচ্ছেদটি আমাকে বাহ্যিকভাবে আরও ইনস্ট্যান্টেশন যুক্ত করতে দেয়। তদ্ব্যতীত, এটি এখনও জুড়তে যখন h/cppমূলটিকে রাখি তবুও আমাকে অন্তর্ভুক্ত প্রহরীতে ইনস্ট্যান্টেশনের মূল তালিকাটি ঘিরে রাখতে হয়েছিল , তবে আমি এখনও foo.cppসাধারণ হিসাবে সংকলন করতে পারি । যদিও আমি সি ++ তে এখনও বেশ নতুন আছি এবং এই মিশ্র ব্যবহারে কোনও অতিরিক্ত ক্যাভ্যাট রয়েছে কিনা তা জানতে আগ্রহী।
থার্ডওয়াটার

3
আমার মনে হয় এটা decouple বাঞ্ছনীয় foo.cppএবং foo-impl.cpp। না #include "foo.cpp"foo-impl.cppফাইল; পরিবর্তে, সংকলনটি সংকলন করার সময় টেমপ্লেট ইনস্ট্যান্ট করা থেকে সংকলককে প্রতিরোধ extern template class foo<int>;করার foo.cppজন্য ঘোষণাটি যুক্ত করুন foo.cpp। নিশ্চিত হয়ে নিন যে বিল্ড সিস্টেম উভয় .cppফাইল তৈরি করে এবং উভয় অবজেক্ট ফাইলকে লিঙ্কারে প্রেরণ করে। এর একাধিক সুবিধা রয়েছে: ক) এটি foo.cppকোনও স্পষ্ট নয় যে কোনও তাত্পর্য নেই; খ) foo.cpp এ পরিবর্তনগুলি foo-impl.cpp এর পুনঃসংশোধনের প্রয়োজন হয় না।
শমুয়েল লেভাইন

3
এটি টেমপ্লেট সংজ্ঞাগুলির সমস্যার খুব ভাল পদ্ধতির যা উভয় বিশ্বের সেরা লাগে - শিরোনাম প্রয়োগ এবং ঘন ঘন ব্যবহৃত ধরণের জন্য ইনস্ট্যান্টেশন ation শুধুমাত্র পরিবর্তন আমি এই সেটআপ করতে হবে নামান্তর হয় foo.cppমধ্যে foo_impl.hএবং foo-impl.cppমাত্র মধ্যে foo.cpp। আমিও typedefs instantiations থেকে যোগ হবে foo.cppথেকে foo.h, অনুরূপভাবে using foo_int = foo<int>;। কৌশলটি হ'ল ব্যবহারকারীদের পছন্দের জন্য দুটি শিরোনাম ইন্টারফেস সরবরাহ করা। যখন ব্যবহারকারীর প্রাক-সংজ্ঞায়িত ইনস্ট্যান্টেশন foo.hপ্রয়োজন হয় যখন সে অন্তর্ভুক্ত থাকে , যখন ব্যবহারকারীর যাতে কিছু অন্তর্ভুক্ত থাকে তবে তার অন্তর্ভুক্ত থাকে foo_impl.h
কিশোর

5

এটি অবশ্যই কোনও বাজে হ্যাক নয়, তবে এই বিষয়টি সম্পর্কে সচেতন হোন যে আপনি প্রদত্ত টেমপ্লেটটি ব্যবহার করতে চান এমন প্রতিটি শ্রেণি / প্রকারের জন্য আপনাকে এটি (স্পষ্টতাল টেম্পলেট বিশেষীকরণ) করতে হবে। অনেক ধরণের ক্ষেত্রে টেম্পলেট ইনস্ট্যান্টেশন অনুরোধ করার ক্ষেত্রে আপনার .cpp ফাইলে প্রচুর লাইন থাকতে পারে। এই সমস্যার প্রতিকারের জন্য আপনার ব্যবহৃত প্রতিটি প্রকল্পে আপনি একটি টেম্পলেটস্লাসইনস্টিপিপি রাখতে পারেন যাতে কোন ধরণের ইনস্ট্যান্ট করা হবে তার উপর আপনার আরও নিয়ন্ত্রণ থাকে। স্পষ্টতই এই সমাধানটি নিখুঁত হবে না (ওরফে সিলভার বুলেট) কারণ আপনি ওডিআর ভঙ্গ করতে পারেন :)।


আপনি কি নিশ্চিত যে এটি ওডিআরটি ভেঙে দেবে? যদি টেম্পলেটস্লাসআইএনটিএসপিপি-তে ইনস্ট্যান্টেশন লাইনগুলি অভিন্ন উত্স ফাইলটি (টেমপ্লেট ফাংশন সংজ্ঞা সম্বলিত) উল্লেখ করে তবে সমস্ত সংজ্ঞা একইরূপে (পুনরাবৃত্তি হলেও) ওডিআর লঙ্ঘন করার নিশ্চয়তা কি নয়?
ড্যান নিসেনবাউম

দয়া করে, ওডিআর কী?
nonremovable

4

সর্বশেষ স্ট্যান্ডার্ডে একটি কীওয়ার্ড ( export) রয়েছে যা এই সমস্যাটি দূর করতে সহায়তা করবে, তবে এটি কমউউ ব্যতীত অন্য কোনও সংকলকের ক্ষেত্রে কার্যকর নয়।

এই সম্পর্কে FAQ- লাইট দেখুন ।


2
আফাইক, রফতানি মরে গেছে কারণ তারা প্রতিটিবার নতুন এবং আরও নতুন সমস্যার মুখোমুখি হচ্ছে, প্রতিবার তারা শেষ সমাধান করে, সামগ্রিক সমাধানটিকে আরও এবং আরও জটিল করে তুলেছে। এবং "রফতানি" কীওয়ার্ড আপনাকে যেভাবেই কোনও সিপিপি থেকে "রফতানি" করতে সক্ষম করবে না (এখনও এইচ। সাটারের যেভাবেই হোক)। তাই আমি বলছি: আপনার শ্বাস ধরে রাখবেন না ...
22:25

2
রফতানি বাস্তবায়নের জন্য সংকলকটির এখনও সম্পূর্ণ টেম্পলেট সংজ্ঞা প্রয়োজন। আপনারা যা অর্জন করেছেন তা সকলে একটি সংকলিত আকারে করছে। তবে সত্যিই এটির কোনও মানে নেই।
ঝ্যান লিংস

2
... এবং এটি ন্যূনতম লাভের জন্য অতিরিক্ত জটিলতার কারণে, মান থেকে দূরে গেছে
দেবসোলার

4

এটি টেমপ্লেট কার্যগুলি সংজ্ঞায়িত করার একটি স্ট্যান্ডার্ড উপায় way আমি মনে করি টেমপ্লেট সংজ্ঞায়িত করার জন্য আমি তিনটি পদ্ধতি পড়েছি। বা সম্ভবত 4. প্রতিটি ভাল এবং কনস সঙ্গে।

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

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

  3. আপনার প্রধান.সি.পি.পিতে শিরোলেখ। এবং বাস্তবায়ন.সি.পি.পি অন্তর্ভুক্ত করুন। আমি মনে করি এটি কিভাবে সম্পন্ন হয়েছে। আপনাকে কোনও প্রাক ইনস্ট্যান্টেশন প্রস্তুত করতে হবে না, এটি একটি সত্য টেম্পলেটটির মতো আচরণ করবে। আমার এটির সমস্যাটি হ'ল এটি স্বাভাবিক নয়। আমরা সাধারণত উত্স ফাইলগুলি অন্তর্ভুক্ত করি না এবং আশা করি না। আমি অনুমান করি যেহেতু আপনি উত্স ফাইলটি অন্তর্ভুক্ত করেছেন, টেম্পলেট ফাংশনগুলি ইনলাইন করা যেতে পারে।

  4. এই শেষ পদ্ধতিটি, যা পোস্ট করা উপায় ছিল, 3 নম্বরের মতো উত্স ফাইলে টেমপ্লেটগুলি সংজ্ঞায়িত করছে; তবে উত্স ফাইলটি অন্তর্ভুক্ত করার পরিবর্তে আমরা আমাদের প্রয়োজনীয় টেমপ্লেটগুলি প্রাক ইনস্ট্যান্ট করি। এই পদ্ধতিটি নিয়ে আমার কোনও সমস্যা নেই এবং এটি কখনও কখনও কাজে আসে। আমাদের একটি বড় কোড রয়েছে, এটি ইনডিল হওয়া থেকে উপকৃত হতে পারে না তাই কেবল এটি একটি সিপিপি ফাইলে রাখুন। এবং যদি আমরা সাধারণ ইনস্ট্যানটিশনগুলি জানি এবং আমরা সেগুলি পূর্বনির্ধারিত করতে পারি। এটি আমাদের মূলত একই জিনিস 5, 10 বার লেখা থেকে বাঁচায়। এই কোডটি আমাদের কোড স্বত্বাধিকারী রাখার সুবিধা রয়েছে। তবে আমি সিপিপি ফাইলগুলিতে ক্ষুদ্র, নিয়মিত ব্যবহৃত ফাংশন রাখার পরামর্শ দিচ্ছি না। এটি আপনার গ্রন্থাগারের কর্মক্ষমতা হ্রাস করবে।

দ্রষ্টব্য, আমি একটি স্ফীতিত আপত্তি ফাইলের পরিণতি সম্পর্কে অবগত নই।


3

হ্যাঁ, যে কাজ করতে মান উপায় specializiation স্পষ্ট ইনস্ট্যান্স। আপনি যেমন বলেছিলেন, আপনি অন্য ধরণের সাথে এই টেমপ্লেটটি ইনস্ট্যান্ট করতে পারবেন না।

সম্পাদনা: মন্তব্যের ভিত্তিতে সংশোধন করা হয়েছে।


পরিভাষা সম্পর্কে বাছাই করা এটি একটি "সুস্পষ্ট তাত্পর্য"।
রিচার্ড কর্ডেন

2

আসুন একটি উদাহরণ নেওয়া যাক, আপনি কোনও টেম্পলেট ক্লাস করতে চান এমন কোনও কারণে আসুন:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

আপনি যদি ভিজ্যুয়াল স্টুডিওতে এই কোডটি সংকলন করেন - এটি বাক্সের বাইরে কাজ করে। জিসিসি লিঙ্কার ত্রুটি তৈরি করবে (যদি একই শিরক ফাইলটি একাধিক .cpp ফাইলগুলি থেকে ব্যবহৃত হয়):

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

বাস্তবায়নটিকে .cpp ফাইলে স্থানান্তরিত করা সম্ভব, তবে তারপরে আপনাকে এই জাতীয় ক্লাস ঘোষণা করতে হবে -

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

এবং তারপরে .cpp এর মতো দেখতে পাবেন:

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

শিরোনাম ফাইলে দুটি শেষ লাইন ছাড়া - জিসিসি ভাল কাজ করবে, তবে ভিজ্যুয়াল স্টুডিও একটি ত্রুটি তৈরি করবে:

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

আপনি .dll রফতানির মাধ্যমে ফাংশনটি প্রকাশ করতে চাইলে টেমপ্লেট শ্রেণীর বাক্য গঠনটি optionচ্ছিক, তবে এটি কেবল উইন্ডোজ প্ল্যাটফর্মের জন্যই প্রযোজ্য - সুতরাং test_template.h এর মতো দেখতে পারা যায়:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

পূর্ববর্তী উদাহরণ থেকে .cpp ফাইল সহ।

এটি লিঙ্কারে আরও মাথা ব্যাথা দেয়, সুতরাং যদি আপনি .dll ফাংশন রফতানি না করেন তবে পূর্ববর্তী উদাহরণটি ব্যবহার করার পরামর্শ দেওয়া হচ্ছে।


1

একটি আপডেটের জন্য সময়! একটি ইনলাইন (.inl, বা অন্য কোনও সম্ভবত) ফাইল তৈরি করুন এবং এতে আপনার সমস্ত সংজ্ঞা অনুলিপি করুন। প্রতিটি ফাংশন ( template <typename T, ...>) এর উপরে টেমপ্লেটটি যুক্ত করতে ভুলবেন না । এখন শিরোনাম ফাইলটি ইনলাইন ফাইলটিতে অন্তর্ভুক্ত করার পরিবর্তে আপনি বিপরীতে করুন। আপনার শ্রেণীর ঘোষণার পরে ইনলাইন ফাইলটি অন্তর্ভুক্ত করুন ( #include "file.inl")।

আমি কেন জানি না কেন কেউ এটি উল্লেখ করেনি। আমি তাত্ক্ষণিক কোনও ত্রুটি দেখতে পাচ্ছি না।


25
তাত্ক্ষণিক ত্রুটিগুলি হ'ল এটি মূলত কেবল শিরোনামে সরাসরি টেম্পলেট ফাংশনগুলি সংজ্ঞায়িত করার মতো। একবার আপনি #include "file.inl", প্রিপ্রোসেসর file.inlসরাসরি শিরোনামের বিষয়বস্তু আটকানো যাচ্ছে । শিরোনামে আপনি প্রয়োগটি এড়াতে যে কারণেই চেয়েছিলেন, এই সমাধানটি এই সমস্যার সমাধান করে না।
কোডি গ্রে

5
- এবং এর অর্থ আপনি প্রযুক্তিগতভাবে অপ্রয়োজনীয়, নিজেকে বোঝাচ্ছেন ডাব্লু / সমস্ত ভার্জবোজ লেখার কাজ, মন-বাঁকানো বয়লারপ্লেটটি বাইরের অফ templateসংজ্ঞা দ্বারা প্রয়োজনীয় । লোকেরা কেন এটি করতে চায় তা পেয়েছি - নন-টেম্পলেট ঘোষণাগুলি / সংজ্ঞা দিয়ে সর্বাধিক সাম্য অর্জন করতে, ইন্টারফেসের ঘোষণাকে পরিপাটি করে রাখা ইত্যাদি - তবে এটি সর্বদা ঝামেলার পক্ষে নয়। এটি উভয় পক্ষের বাণিজ্য-মূল্যায়ন মূল্যায়নের এবং কমপক্ষে খারাপটি বাছাইয়ের একটি বিষয় । ... যতক্ষণ না namespace classকোনও জিনিস হয়ে ওঠে: ও [ দয়া করে একটি জিনিস হয়ে যান ]
2:58

2
@ অ্যান্ড্রু মনে হচ্ছে কমিটির পাইপগুলিতে আটকে গেছে, যদিও আমি মনে করি যে আমি কাউকে বলতে দেখেছি যে এটি উদ্দেশ্যমূলক ছিল না। আমি চাই এটি এটিকে C ++ 17 বানিয়েছে। আগামী দশক হতে পারে।
আন্ডারস্কোর_ডি

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

0

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

সুস্পষ্ট শ্রেণীর ইনস্ট্যান্টেশন সহ একসাথে ব্যবহার করা হলে, বুস্ট কনসেপ্ট চেক লাইব্রেরি (বিসিসিএল) আপনাকে সিপিপি ফাইলগুলিতে টেমপ্লেট ফাংশন কোড তৈরি করতে সহায়তা করতে পারে।


8
এটি সম্পর্কে অদক্ষতা কি?
কোডি গ্রে

0

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

class Model
{
    template <class T>
    void build(T* b, uint32_t number);
};

.cpp

#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
    //implementation
}

void TemporaryFunction()
{
    Model m;
    m.build<B1>(new B1(),1);
    m.build<B2>(new B2(), 1);
    m.build<B3>(new B3(), 1);
}

এটি লিঙ্কারের ত্রুটিগুলি এড়ায় এবং টেম্পোরারি ফাংশনটি একেবারে কল করার দরকার নেই

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