@ ডেভিড রদ্রিগিজের উত্তর - ড্রিবিয়াস টাইপ-ইরেজ প্রদর্শনের জন্য ভাল তবে টাইপ-ইরেজারে কীভাবে কপি করা হয় তাও অন্তর্ভুক্ত নয় (এর উত্তরে ফাংশন অবজেক্টটি কপি-গঠনযোগ্য হবে না)। এই আচরণগুলি function
ফান্টারের ডেটার পাশাপাশি বস্তুতেও সংরক্ষণ করা হয় ।
উবুন্টু 14.04 জিসিসি 4.8 থেকে এসটিএল বাস্তবায়নে ব্যবহৃত কৌশলটি হ'ল একটি জেনেরিক ফাংশন রচনা করা, এটি প্রতিটি সম্ভাব্য ফান্টারের ধরণের সাথে বিশেষজ্ঞ করা, এবং তাদের সর্বজনীন ফাংশন পয়েন্টার টাইপে ফেলে দেওয়া। সুতরাং টাইপ তথ্য মুছে ফেলা হয় ।
আমি এর একটি সরলীকৃত সংস্করণ আঁকিয়েছি। আশা করি এটি সাহায্য করবে
#include <iostream>
#include <memory>
template <typename T>
class function;
template <typename R, typename... Args>
class function<R(Args...)>
{
typedef R (*invoke_fn_t)(char*, Args&&...);
typedef void (*construct_fn_t)(char*, char*);
typedef void (*destroy_fn_t)(char*);
template <typename Functor>
static R invoke_fn(Functor* fn, Args&&... args)
{
return (*fn)(std::forward<Args>(args)...);
}
template <typename Functor>
static void construct_fn(Functor* construct_dst, Functor* construct_src)
{
new (construct_dst) Functor(*construct_src);
}
template <typename Functor>
static void destroy_fn(Functor* f)
{
f->~Functor();
}
invoke_fn_t invoke_f;
construct_fn_t construct_f;
destroy_fn_t destroy_f;
std::unique_ptr<char[]> data_ptr;
size_t data_size;
public:
function()
: invoke_f(nullptr)
, construct_f(nullptr)
, destroy_f(nullptr)
, data_ptr(nullptr)
, data_size(0)
{}
template <typename Functor>
function(Functor f)
: invoke_f(reinterpret_cast<invoke_fn_t>(invoke_fn<Functor>))
, construct_f(reinterpret_cast<construct_fn_t>(construct_fn<Functor>))
, destroy_f(reinterpret_cast<destroy_fn_t>(destroy_fn<Functor>))
, data_ptr(new char[sizeof(Functor)])
, data_size(sizeof(Functor))
{
this->construct_f(this->data_ptr.get(), reinterpret_cast<char*>(&f));
}
function(function const& rhs)
: invoke_f(rhs.invoke_f)
, construct_f(rhs.construct_f)
, destroy_f(rhs.destroy_f)
, data_size(rhs.data_size)
{
if (this->invoke_f) {
this->data_ptr.reset(new char[this->data_size]);
this->construct_f(this->data_ptr.get(), rhs.data_ptr.get());
}
}
~function()
{
if (data_ptr != nullptr) {
this->destroy_f(this->data_ptr.get());
}
}
R operator()(Args&&... args)
{
return this->invoke_f(this->data_ptr.get(), std::forward<Args>(args)...);
}
};
int main()
{
int i = 0;
auto fn = [i](std::string const& s) mutable
{
std::cout << ++i << ". " << s << std::endl;
};
fn("first");
fn("second");
::function<void(std::string const&)> f(fn);
f("third");
::function<void(std::string const&)> g(f);
f("forth - f");
g("forth - g");
std::string x("xxxx");
::function<void()> h([x]() { std::cout << x << std::endl; });
h();
::function<void()> k(h);
k();
return 0;
}
এসটিএল সংস্করণে কিছু অপ্টিমাইজেশন রয়েছে
construct_f
এবং destroy_f
কিছু বাইট সংরক্ষণ করতে (একটি অতিরিক্ত প্যারামিটার বলে যে কি করতে হবে তা সহ) এক ফাংশন পয়েন্টার মধ্যে মিশিয়ে দেওয়া হয়
- কাঁচা পয়েন্টারগুলি এ ফাংশন পয়েন্টার সহ ফান্টেক্টর অবজেক্টটি সংরক্ষণ করতে ব্যবহৃত হয়
union
, যাতে যখন function
কোনও ফাংশন পয়েন্টার থেকে কোনও বস্তুটি তৈরি করা হয়, তখন এটি union
গাদা স্থানের পরিবর্তে সরাসরি সংরক্ষণ করা হবে
আমি এসটিএল বাস্তবায়ন সর্বোত্তম সমাধান নয় কারণ আমি কিছু দ্রুত বাস্তবায়ন সম্পর্কে শুনেছি । তবে আমি বিশ্বাস করি অন্তর্নিহিত প্রক্রিয়াটি একই।
std::function
কিছুক্ষণ আগে জিসিসি / স্টাডলিব বাস্তবায়নের দিকে নজর রেখেছিলাম । এটি মূলত একটি বহুকোষযুক্ত বস্তুর জন্য একটি হ্যান্ডেল শ্রেণি। অভ্যন্তরীণ বেস শ্রেণীর একটি উত্পন্ন ক্লাসটি গাদাগুলিতে বরাদ্দকৃত পরামিতিগুলি ধরে রাখার জন্য তৈরি করা হয় - তারপরে এটির পয়েন্টারটি একটি সাবোবজেক্ট হিসাবে ধরা হয়std::function
। আমি বিশ্বাস করি এটিstd::shared_ptr
অনুলিপি এবং চলন পরিচালনা করতে পছন্দসই গণনা ব্যবহার করে ।