একটি রুট অবজেক্ট থাকার কারণে আপনি কী করতে পারেন এবং সংকলকটি কি করতে পারে তা সীমাবদ্ধ করে দেয় না much
একটি সাধারণ রুট শ্রেণি যেকোনও পাত্রে তৈরি করা এবং সেগুলির সাথে কী রয়েছে তা বের করা সম্ভব করে তোলে dynamic_cast
, তবে আপনার যদি কিছু পাত্রে প্রয়োজন হয় তবে সাধারণ রুট শ্রেণি ছাড়াইboost::any
এটি করার মতো কিছু । এবং আদিমদেরও সমর্থন করে - এটি এমনকি ছোট বাফার অপ্টিমাইজেশানকে সমর্থন করতে পারে এবং তাদের জাভা পার্লেন্সে প্রায় "আনবক্সড" রেখে যেতে পারে।boost::any
সি ++ মান ধরণের উপর সমর্থন করে এবং সাফল্য লাভ করে। উভয় আক্ষরিক এবং প্রোগ্রামার লিখিত মান প্রকার। সি ++ পাত্রে দক্ষতার সাথে স্টোর, বাছাই, হ্যাশ, গ্রাহক এবং মান ধরণের উত্পাদন করা হয়।
উত্তরাধিকার, বিশেষত একজাতীয় উত্তরাধিকারের ধরণের জাভা স্টাইলের বেস ক্লাসগুলি বোঝায়, ফ্রি-স্টোর ভিত্তিক "পয়েন্টার" বা "রেফারেন্স" প্রকারের প্রয়োজন। আপনার হ্যান্ডেল / পয়েন্টার / ডেটাতে রেফারেন্সটি ক্লাসের ইন্টারফেসে একটি পয়েন্টার ধারণ করে, এবং বহুতলিকভাবে অন্য কোনও উপস্থাপনা করতে পারে।
যদিও এটি কিছু পরিস্থিতিতে কার্যকর হয়, একবার আপনি "প্রচলিত বেস শ্রেণি" দিয়ে প্যাটার্নটিতে নিজেকে বিয়ে করার পরে, আপনি আপনার পুরো কোড বেসটি এই প্যাটার্নটির ব্যয় এবং লাগেজের মধ্যে লক করে রেখেছেন, এমনকি এটি কার্যকর না হলেও।
প্রায় সবসময় আপনি কলিং সাইটে হয়, বা কোডটি ব্যবহার করে যে কোনও কোডে "এটি একটি বস্তু" এর চেয়ে কোনও ধরণের সম্পর্কে আরও বেশি জানেন।
যদি ফাংশনটি সহজ হয় তবে ফাংশনটি টেমপ্লেট হিসাবে লেখার ফলে আপনি হাঁসের ধরণের সংকলনকে সময় ভিত্তিক বহুবৈচিত্র্য সরবরাহ করেন যেখানে কলিং সাইটে তথ্য দূরে নিক্ষেপ করা হয় না। যদি ফাংশনটি আরও জটিল হয় তবে টাইপ মুছে ফেলা যেতে পারে যার মাধ্যমে আপনি যে ধরণের সঞ্চালন করতে চান (একইভাবে সিরিয়ালাইজেশন এবং ডিসরিয়ালাইজেশন) এর ইউনিফর্ম ক্রিয়াকলাপগুলি তৈরি করতে এবং সংরক্ষণ করতে (সংকলন সময়ে) গ্রাস করতে হবে (রান সময়ে) একটি ভিন্ন অনুবাদ ইউনিট কোড।
মনে করুন আপনার কাছে এমন কিছু লাইব্রেরি রয়েছে যেখানে আপনি চান সমস্ত কিছু সিরিয়ালযোগ্য হতে পারে। একটি পদ্ধতির একটি বেস শ্রেণি আছে:
struct serialization_friendly {
virtual void write_to( my_buffer* ) const = 0;
virtual void read_from( my_buffer const* ) = 0;
virtual ~serialization_friendly() {}
};
এখন আপনার লেখার প্রতিটি বিট কোড হতে পারে serialization_friendly
।
void serialize( my_buffer* b, serialization_friendly const* x ) {
if (x) x->write_to(b);
}
এ ব্যতীত std::vector
, এখন আপনার প্রতিটি পাত্রে লেখার প্রয়োজন। এবং আপনি যে বিগনাম লাইব্রেরি থেকে প্রাপ্ত পূর্ণসংখ্যাগুলি পান না। এবং সেই ধরণের নয় আপনি লিখেছেন যে আপনি সিরিয়ালাইজেশন প্রয়োজন বলে মনে করেন নি। এবং না একটি tuple
, বা একটি int
বা একটি double
, বা এstd::ptrdiff_t
।
আমরা অন্য পদ্ধতি গ্রহণ:
void write_to( my_buffer* b, int x ) {
b->write_integer(x);
}
template<class T,
class=std::enable_if_t< void_t<
std::declval<T const*>()->write_to( std::declval<my_buffer*>()
> >
>
void write_to( my_buffer* b, T const* x ) {
if (x) x->write_to(b);
}
template<class T>
void serialize( my_buffer* b, T const& t ) {
write_to( b, t );
}
যা সমন্বিত, ভাল, কিছুই করছেন না বলে মনে হচ্ছে। এখন ব্যতীত আমরা কোনও প্রকারের নামস্থানে বা কোনও ধরণের কোনও পদ্ধতিতে একটি মুক্ত ফাংশন হিসাবে write_to
ওভাররাইড করে প্রসারিত করতে পারি write_to
।
এমনকি আমরা মুছে ফেলা কোডের প্রকারটিও লিখতে পারি:
namespace details {
struct can_serialize_pimpl {
virtual void write_to( my_buffer* ) const = 0;
virtual void read_from( my_buffer const* ) = 0;
virtual ~can_serialize_pimpl() {}
};
}
struct can_serialize {
void write_to( my_buffer* b ) const { pImpl->write_to(b); }
void read_from( my_buffer const* b ) { pImpl->read_from(b); }
std::unique_ptr<details::can_serialize_pimpl> pImpl;
template<class T> can_serialize(T&&);
};
namespace details {
template<class T>
struct can_serialize : can_serialize_pimpl {
std::decay_t<T>* t;
void write_to( my_buffer*b ) const final override {
serialize( b, std::forward<T>(*t) );
}
void read_from( my_buffer const* ) final override {
deserialize( b, std::forward<T>(*t) );
}
can_serialize(T&& in):t(&in) {}
};
}
template<class T> can_serialize::can_serialize<T>(T&&t):pImpl(
std::make_unique<details::can_serialize<T>>( std::forward<T>(t) );
) {}
এবং এখন আমরা একটি স্বেচ্ছাসেবী টাইপ নিতে পারি এবং এটি একটি can_serialize
ইন্টারফেসে অটো-বক্স করতে পারি যা আপনাকে serialize
ভার্চুয়াল ইন্টারফেসের মাধ্যমে পরবর্তী সময়ে প্রার্থনা করতে দেয় ।
তাই:
void writer_thingy( can_serialize s );
এর পরিবর্তে সিরিয়ালাইজ করতে পারে এমন কোনও কিছু এমন ফাংশন
void writer_thingy( serialization_friendly const* s );
এবং প্রথমটি, দ্বিতীয়টির থেকে ভিন্ন, এটি পরিচালনা করতে পারে int
,std::vector<std::vector<Bob>>
স্বয়ংক্রিয়ভাবে।
এটি লিখতে খুব বেশি লাগেনি, বিশেষত কারণ এই ধরণের জিনিস এমন একটি জিনিস যা আপনি খুব কমই করতে চান, তবে আমরা কোনও বেস ধরণের প্রয়োজন ছাড়াই কোনও কিছুকে সিরিয়ালযোগ্য হিসাবে বিবেচনা করার ক্ষমতা অর্জন করেছি।
আরও কী, আমরা এখন std::vector<T>
ওভাররাইড করে প্রথম শ্রেণির নাগরিক হিসাবে সিরিয়ালীকরণযোগ্য করতে পারি write_to( my_buffer*, std::vector<T> const& )
- সেই ওভারলোডের সাহায্যে এটি একটিতে চলে যেতে পারে can_serialize
এবং এর সিরিয়ালজ্যাবিলিটটি std::vector
একটি ভিটিবেলে সংরক্ষণ করা হয় এবং এর মাধ্যমে অ্যাক্সেস করা যায় .write_to
।
সংক্ষেপে, সি ++ যথেষ্ট শক্তিশালী যে আপনি যখন প্রয়োজন হয় তখন জোরপূর্বক উত্তরাধিকারের স্তরক্রমের মূল্য প্রদান না করেই অন-দ্য ফ্লাইতে একক বেস শ্রেণীর সুবিধাগুলি কার্যকর করতে পারেন। এবং একক বেস (নকল বা না) প্রয়োজনীয় সময়গুলি যথাযথ বিরল।
যখন প্রকারগুলি আসলে তাদের পরিচয় হয় এবং আপনি কী সেগুলি জানেন তবেই অপ্টিমাইজেশনের সুযোগগুলি প্রচুর। ডেটা স্থানীয়ভাবে এবং স্বচ্ছলভাবে সংরক্ষণ করা হয় (যা আধুনিক প্রসেসরের উপর ক্যাশে বন্ধুত্বের জন্য অত্যন্ত গুরুত্বপূর্ণ), সংকলকরা সহজেই বুঝতে পারে যে প্রদত্ত ক্রিয়াকলাপটি কী করে (পরিবর্তে একটি অস্বচ্ছ ভার্চুয়াল পদ্ধতি পয়েন্টার যার উপরে ঝাঁপিয়ে পড়েছে তার পরিবর্তে, অজানা কোডের দিকে চালিত করে অন্যদিকে) যা নির্দেশাবলীকে সর্বোত্তমভাবে পুনঃক্রম করতে দেয় এবং কম গোলাকার খোঁচাগুলি বৃত্তাকার গর্তগুলিতে পরিণত হয়।