মুছে ফেলার কৌশলগুলি টাইপ করুন


136

(টাইপ ইরেজিওর, আমি একটি বর্গ, কিছুটা মত সংক্রান্ত কিছু বা টাইপ সমস্ত তথ্য গোপন অর্থ Boost.Any ।)
আমি টাইপ ইরেজিওর কৌশল হোল্ড পেতে চান, যখন সেই, যা আমি জানি ভাগ করুন। আমার আশা এমন কিছু পাগল কৌশলটি সন্ধান করতে চাই যা তার সবচেয়ে অন্ধকার সময়ে কেউ ভেবেছিল। :)

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

তারপরে ফাংশন পয়েন্টারগুলির সাথে টেম্পলেটড ফাংশনগুলির বিকল্প রয়েছে, যখন void*পয়েন্টারটিতে আসল অবজেক্টটি ধরে রাখার মতো বুস্ট un ফাংশন ফান্টারের আসল ধরণের আড়াল করতে পারে। প্রশ্নের শেষে উদাহরণ প্রয়োগগুলি পাওয়া যাবে।

সুতরাং, আমার আসল প্রশ্নটির জন্য:
অন্য কোন ধরণের ক্ষয় কৌশল আপনি কী জানেন? যদি তাদের সম্ভব হয় তবে একটি উদাহরণ কোড সহ কেসগুলি ব্যবহার করুন, তাদের সাথে আপনার অভিজ্ঞতা এবং আরও পড়ার জন্য লিঙ্কগুলি সরবরাহ করুন links

সম্পাদনা
(যেহেতু আমি নিশ্চিত ছিলাম না যে এটিকে উত্তর হিসাবে যুক্ত করা, বা কেবলমাত্র প্রশ্নটি সম্পাদনা করা, আমি কেবল নিরাপদটি করব do) ভার্চুয়াল ফাংশন বা ফিডিং ছাড়া
প্রকৃত ধরণের কোনও কিছু আড়াল করার জন্য আরেকটি দুর্দান্ত কৌশল void*হ'ল একজন GMan এখানে নিযুক্ত আছেন , আমার প্রশ্নের সাথে প্রাসঙ্গিকতার সাথে এটি ঠিক কীভাবে কাজ করে তা।


উদাহরণ কোড:

#include <iostream>
#include <string>

// NOTE: The class name indicates the underlying type erasure technique

// this behaves like the Boost.Any type w.r.t. implementation details
class Any_Virtual{
        struct holder_base{
                virtual ~holder_base(){}
                virtual holder_base* clone() const = 0;
        };

        template<class T>
        struct holder : holder_base{
                holder()
                        : held_()
                {}

                holder(T const& t)
                        : held_(t)
                {}

                virtual ~holder(){
                }

                virtual holder_base* clone() const {
                        return new holder<T>(*this);
                }

                T held_;
        };

public:
        Any_Virtual()
                : storage_(0)
        {}

        Any_Virtual(Any_Virtual const& other)
                : storage_(other.storage_->clone())
        {}

        template<class T>
        Any_Virtual(T const& t)
                : storage_(new holder<T>(t))
        {}

        ~Any_Virtual(){
                Clear();
        }

        Any_Virtual& operator=(Any_Virtual const& other){
                Clear();
                storage_ = other.storage_->clone();
                return *this;
        }

        template<class T>
        Any_Virtual& operator=(T const& t){
                Clear();
                storage_ = new holder<T>(t);
                return *this;
        }

        void Clear(){
                if(storage_)
                        delete storage_;
        }

        template<class T>
        T& As(){
                return static_cast<holder<T>*>(storage_)->held_;
        }

private:
        holder_base* storage_;
};

// the following demonstrates the use of void pointers 
// and function pointers to templated operate functions
// to safely hide the type

enum Operation{
        CopyTag,
        DeleteTag
};

template<class T>
void Operate(void*const& in, void*& out, Operation op){
        switch(op){
        case CopyTag:
                out = new T(*static_cast<T*>(in));
                return;
        case DeleteTag:
                delete static_cast<T*>(out);
        }
}

class Any_VoidPtr{
public:
        Any_VoidPtr()
                : object_(0)
                , operate_(0)
        {}

        Any_VoidPtr(Any_VoidPtr const& other)
                : object_(0)
                , operate_(other.operate_)
        {
                if(other.object_)
                        operate_(other.object_, object_, CopyTag);
        }

        template<class T>
        Any_VoidPtr(T const& t)
                : object_(new T(t))
                , operate_(&Operate<T>)
        {}

        ~Any_VoidPtr(){
                Clear();
        }

        Any_VoidPtr& operator=(Any_VoidPtr const& other){
                Clear();
                operate_ = other.operate_;
                operate_(other.object_, object_, CopyTag);
                return *this;
        }

        template<class T>
        Any_VoidPtr& operator=(T const& t){
                Clear();
                object_ = new T(t);
                operate_ = &Operate<T>;
                return *this;
        }

        void Clear(){
                if(object_)
                        operate_(0,object_,DeleteTag);
                object_ = 0;
        }

        template<class T>
        T& As(){
                return *static_cast<T*>(object_);
        }

private:
        typedef void (*OperateFunc)(void*const&,void*&,Operation);

        void* object_;
        OperateFunc operate_;
};

int main(){
        Any_Virtual a = 6;
        std::cout << a.As<int>() << std::endl;

        a = std::string("oh hi!");
        std::cout << a.As<std::string>() << std::endl;

        Any_Virtual av2 = a;

        Any_VoidPtr a2 = 42;
        std::cout << a2.As<int>() << std::endl;

        Any_VoidPtr a3 = a.As<std::string>();
        a2 = a3;
        a2.As<std::string>() += " - again!";
        std::cout << "a2: " << a2.As<std::string>() << std::endl;
        std::cout << "a3: " << a3.As<std::string>() << std::endl;

        a3 = a;
        a3.As<Any_Virtual>().As<std::string>() += " - and yet again!!";
        std::cout << "a: " << a.As<std::string>() << std::endl;
        std::cout << "a3->a: " << a3.As<Any_Virtual>().As<std::string>() << std::endl;

        std::cin.get();
}

1
"টাইপ ইরেজর" দ্বারা, আপনি কি সত্যিই "পলিমারফিজম" উল্লেখ করছেন? আমি মনে করি "টাইপ ইরেজর" এর কিছুটা নির্দিষ্ট অর্থ রয়েছে, যা সাধারণত জাভা জেনেরিকের সাথে জড়িত।
অলিভার চার্লসওয়ার্থ

3
@ অলি: প্রকার মুছে ফেলা বহুবর্ষের সাথে প্রয়োগ করা যেতে পারে, তবে এটি একমাত্র বিকল্প নয়, আমার দ্বিতীয় উদাহরণটি এটি দেখায়। :) এবং মুছে ফেলা টাইপের সাথে আমি ঠিক বলতে চাইছি, আপনার স্ট্রাক্ট উদাহরণস্বরূপ কোনও টেম্পলেট ধরণের উপর নির্ভর করে না। আপনি এটিকে কোনও ফান্টেক্টর, একটি ফাংশন পয়েন্টার, এমনকি ল্যাম্বদা খাওয়ান কিনা তা বুস্ট.ফানশনের কোনও যত্ন নেই। বুস্ট.শারেড_পিটিআরের সাথে একই। আপনি একটি বরাদ্দকারী এবং ডিওলোকেশন ফাংশন নির্দিষ্ট করতে পারেন, তবে প্রকৃত প্রকারটি shared_ptrএটি প্রতিফলিত করে না, এটি সর্বদা একই হবে, shared_ptr<int>উদাহরণস্বরূপ, মানক ধারক থেকে ভিন্ন।
জিও

2
@ ম্যাথিউ: আমি দ্বিতীয় উদাহরণটিকেও নিরাপদ বলে বিবেচনা করি। আপনি যে সঠিক ধরণের অপারেট করছেন তা আপনি সর্বদা জানেন। নাকি আমি কিছু মিস করছি?
জিও

2
@ ম্যাথিউ: আপনি ঠিক বলেছেন। সাধারণত এই জাতীয় As(গুলি) ফাংশনটি সেভাবে কার্যকর করা হবে না। যেমনটি আমি বলেছি, কোনওভাবেই নিরাপদ ব্যবহারের উপায় নেই! :)
শিও

4
@lurscher আচ্ছা ... বুস্ট বা এসটিডি সংস্করণ আর কখনও ব্যবহৃত কোনো নিচের? function, shared_ptr, any, ইত্যাদি? তারা সকলেই মিষ্টি মিষ্টি ব্যবহারকারীর সুবিধার জন্য মুছে ফেলা ধরণের কাজ করে।
Xoo

উত্তর:


100

সি ++ তে সমস্ত ধরণের ক্ষয় কৌশলগুলি ফাংশন পয়েন্টার (আচরণের জন্য) এবং void*(ডেটার জন্য ) দিয়ে সম্পন্ন হয় । "বিভিন্ন" পদ্ধতিগুলি সিমেটিক চিনি যুক্ত করার সাথে কেবল তারতম্য। ভার্চুয়াল ফাংশন, উদাহরণস্বরূপ, এর জন্য কেবল শব্দার্থ চিনি

struct Class {
    struct vtable {
        void (*dtor)(Class*);
        void (*func)(Class*,double);
    } * vtbl
};

iow: ফাংশন পয়েন্টার।

এটি বলেছিল, একটি কৌশল রয়েছে যা আমি বিশেষত পছন্দ করি: এটি shared_ptr<void>কেবল কারণ এটি এমন লোকদের মনকে উড়িয়ে দেয় যা আপনি জানেন না যে আপনি এটি করতে পারেন: আপনি কোনও ডেটা একটিতে সঞ্চয় করতে পারেন shared_ptr<void>, এবং ঠিক সেখানে ডাস্ট্রস্ট্রাক্টর ডেকেছেন শেষ, কারণ shared_ptrকনস্ট্রাক্টর একটি ফাংশন টেম্পলেট এবং এটি ডিফল্টরূপে মুছে ফেলা তৈরির জন্য পাস করা প্রকৃত বস্তুর প্রকারটি ব্যবহার করবে:

{
    const shared_ptr<void> sp( new A );
} // calls A::~A() here

অবশ্যই এটি কেবল সাধারণ void*/ ফাংশন-পয়েন্টার প্রকারের ক্ষয়, তবে খুব স্বাচ্ছন্দ্যে প্যাকেজড।


9
কাকতালীয়ভাবে, shared_ptr<void>কিছু দিন আগে আমাকে একটি উদাহরণ প্রয়োগের সাথে আমার এক বন্ধুর সাথে আচরণ সম্পর্কে ব্যাখ্যা করতে হয়েছিল । :) এটা সত্যিই দুর্দান্ত।
Xoo

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

সুতরাং, যদি ভাগ করা_পিটার তারপরে একটি ডারাইভড * সংরক্ষণ করে তবে বেস * ডিস্ট্রাক্টরকে ভার্চুয়াল হিসাবে ঘোষণা করেনি, শেয়ারড_প্টার <void> এখনও উদ্দিষ্ট হিসাবে কাজ করে, যেহেতু এটি কখনই বেস ক্লাসটি শুরু হওয়ার বিষয়ে জানত না। শান্ত!
TamaMcGlinn

@Apollys: এটা না, কিন্তু unique_ptrdeleter নেই টাইপ-নিশ্চিহ্ন, তাই আপনি যদি একটি নির্ধারণ করতে চান unique_ptr<T>একটি থেকে unique_ptr<void>, আপনি স্পষ্টভাবে একটি deleter যুক্তি প্রদান করতে, জানে যে মুছবেন তা Tএকটি মাধ্যমে void*। আপনি এখন একটি দায়িত্ব অর্পণ করতে চান S, অত্যধিক, তাহলে আপনি একটি deleter প্রয়োজন স্পষ্টভাবে, যে জানে কিভাবে মুছে ফেলতে Tএকটি মাধ্যমে void*একটি এবং Sএকটি মাধ্যমে void*, এবং , একটি প্রদত্ত void*, জানে কিনা এটি একটি এর Tঅথবা একটি S। এই মুহুর্তে, আপনি একটি টাইপ-মোছা মুছে ফেলার জন্য লিখেছেন unique_ptrএবং তারপরে এটিও কাজ করে unique_ptr। বাক্সের বাইরে না।
মার্ক মুটজ - মিমুতজ

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

54

মূলত, সেগুলি আপনার বিকল্পগুলি: ভার্চুয়াল ফাংশন বা ফাংশন পয়েন্টার।

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

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


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

কমপক্ষে 2 টি অপশন রয়েছে। আমি একটি উত্তর রচনা করছি।
জন ডিবলিং

25

আমিও বিবেচনা হবে (অনুরূপ void*) "কাঁচা স্টোরেজ" এর ব্যবহার: char buffer[N]

সি ++ 0x এ আপনার std::aligned_storage<Size,Align>::typeজন্য রয়েছে।

আপনি নিজের ইচ্ছামত যে কোনও কিছু সেখানে সংরক্ষণ করতে পারবেন, যতক্ষণ না এটি যথেষ্ট ছোট এবং আপনি সঠিকভাবে সারিবদ্ধভাবে মোকাবেলা করেন।


4
হ্যাঁ, বুস্ট। ফাংশন আসলে এটির এবং আমার দেওয়া দ্বিতীয় উদাহরণটির সংমিশ্রণটি ব্যবহার করে। যদি ফান্টকারটি যথেষ্ট ছোট হয় তবে এটি এটিকে অভ্যন্তরীণভাবে ফান্টেক্টর_বাফারের ভিতরে সঞ্চয় করে। std::aligned_storageযদিও সম্পর্কে জানা ভাল , ধন্যবাদ! :)
শিও

আপনি এর জন্য নতুন প্লেসমেন্টও ব্যবহার করতে পারেন ।
rustyx

2
@RustyX: বাস্তবিক, আপনি আছে হয়। std::aligned_storage<...>::typeএটি কেবল একটি কাঁচা বাফার যা ভিন্ন char [sizeof(T)], যথাযথভাবে সংযুক্ত থাকে। নিজেই, যদিও এটি জড়: এটি এর স্মৃতিশক্তি আরম্ভ করে না, কোনও বস্তু তৈরি করে না, কিছুই করে না। অতএব, আপনি যখন এই ধরণের বাফারটি পেয়ে থাকেন তবে আপনাকে নিজে নিজে এটির ভিতরে বস্তুগুলি তৈরি করতে হবে (উভয় স্থান নির্ধারণ newবা বরাদ্দ constructপদ্ধতি সহ) এবং আপনাকে নিজে নিজে এটির অভ্যন্তরগুলিও ধ্বংস করতে হবে (হয় ম্যানুয়ালি তাদের ডেস্ট্রাক্টরকে প্রার্থনা করা বা একটি বরাদ্দ destroyপদ্ধতি ব্যবহার করে) )।
ম্যাথিউ এম।

22

স্ট্রোভস্ট্রুপের, ইন সি ++ ভাষা প্রোগ্রামিং (4 র্থ সংস্করণ) §25.3 , রাজ্য:

বিভিন্ন ধরণের মূল্যবোধের জন্য একক রুট-টাইম উপস্থাপনা ব্যবহার করার কৌশল (এবং স্থিতিশীল) টাইপ সিস্টেমের উপর নির্ভর করার কৌশলগুলি যেগুলি কেবল তাদের ঘোষিত প্রকার অনুসারে ব্যবহৃত হয় তা টাইপ ইরেজর বলা হয় ।

বিশেষত, ভার্চুয়াল ফাংশন বা ফাংশন পয়েন্টারগুলির কোনও ব্যবহারের প্রয়োজন নেই যদি আমরা টেমপ্লেটগুলি ব্যবহার করি তবে টাইপ ইরেজোর সঞ্চালন করতে হবে। ইতিমধ্যে অন্য জবাবগুলিতে উল্লিখিত কেস, এ এর ​​মধ্যে সংরক্ষিত ধরণ অনুযায়ী সঠিক ডেস্ট্রাক্টর কল এর std::shared_ptr<void>একটি উদাহরণ।

স্ট্রোস্ট্রপের বইয়ে দেওয়া উদাহরণটি যেমন উপভোগযোগ্য তেমনই।

বাস্তবায়ন সম্পর্কে চিন্তা করুন template<class T> class Vector, লাইন বরাবর একটি ধারক std::vector। আপনি যখন Vectorবিভিন্ন পয়েন্টার প্রকারের সাথে আপনার ব্যবহার করবেন , কারণ এটি প্রায়শই ঘটে থাকে, সংকলকটি প্রতিটি পয়েন্টার ধরণের জন্য অবশ্যই আলাদা কোড তৈরি করবে।

এই কোড ফোলানো একটি বিশেষজ্ঞতা সংজ্ঞা দ্বারা প্রতিরোধ করা যায় ভেক্টর জন্য void*পয়েন্টার এবং তারপর একটি সাধারণ বেস বাস্তবায়ন হিসাবে এই বিশেষজ্ঞতা ব্যবহার Vector<T*>অন্যান্যদের ধরনের জন্য T:

template<typename T>
class Vector<T*> : private Vector<void*>{
// all the dirty work is done once in the base class only 
public:
    // ...
    // static type system ensures that a reference of right type is returned
    T*& operator[](size_t i) { return reinterpret_cast<T*&>(Vector<void*>::operator[](i)); }
};

যেহেতু আপনি দেখতে পারেন, আমরা একটি শক্তিশালী ভাবে টাইপ ধারক কিন্তু আছে Vector<Animal*>, Vector<Dog*>, Vector<Cat*>, ..., একই (সি ++ ভাগ করবে এবং তাদের পয়েন্টার টাইপ থাকার বাইনারি) বাস্তবায়নের কোড, মুছে ফেলা পিছনে void*


2
নিন্দিত হওয়া অর্থহীন: আমি স্ট্রাস্ট্রাপের দেওয়া কৌশলটির চেয়ে সিআরটিপি পছন্দ করব।
দবিধিঘরের

@ ডেভিডইহহ আপনার অর্থ কি?
পাওলো এম

এক একটি ব্যবহার করে (ক কম akward সিনট্যাক্স সঙ্গে) একই আচরণ পেতে পারেন CRTP বেস বর্গ template<typename Derived> VectorBase<Derived>যা পরে যেমন বিশেষজ্ঞ template<typename T> VectorBase<Vector<T*> >। তদুপরি, এই পদ্ধতিটি কেবল পয়েন্টারগুলির জন্যই কাজ করে না, তবে যে কোনও প্রকারের জন্য।
ডেভিডিঘ

3
নোট করুন যে ভাল সি ++ লিঙ্কারগুলি অভিন্ন পদ্ধতি এবং ফাংশনগুলিকে একত্রিত করে: সোনার লিঙ্কার, বা এমএসভিসি কমড্যাট ফোল্ডিং। কোড তৈরি করা হয়, তবে লিঙ্ক করার সময় বাতিল করা হয়।
ইয়াক্ক - অ্যাডাম নেভ্রামাউন্ট

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

19

: একটি (মোটামুটি সংক্ষিপ্ত) টাইপ ইরেজিওর কৌশল তালিকা এবং বিনিময় প্রথা সম্পর্কে আলোচনার জন্য পোস্টের মধ্যে এই সিরিজের দেখুন পার্ট আমি , পার্ট II , পার্ট III , পার্ট চতুর্থ

আমি এখনও যা উল্লেখ করি নি সে হ'ল অ্যাডোব.পলি , এবং বুস্ট.ভেরিয়েন্ট , যা কিছুটা প্রকারের ক্ষয় হিসাবে বিবেচিত হতে পারে।


7

মার্কের বক্তব্য অনুসারে, কেউ কাস্ট ব্যবহার করতে পারেন std::shared_ptr<void>। উদাহরণস্বরূপ কোনও ফাংশন পয়েন্টারে টাইপটি সংরক্ষণ করুন , এটি কাস্ট করুন এবং কেবল একটি প্রকারের ফান্টারে সংরক্ষণ করুন:

#include <iostream>
#include <memory>
#include <functional>

using voidFun = void(*)(std::shared_ptr<void>);

template<typename T>
void fun(std::shared_ptr<T> t)
{
    std::cout << *t << std::endl;
}

int main()
{
    std::function<void(std::shared_ptr<void>)> call;

    call = reinterpret_cast<voidFun>(fun<std::string>);
    call(std::make_shared<std::string>("Hi there!"));

    call = reinterpret_cast<voidFun>(fun<int>);
    call(std::make_shared<int>(33));

    call = reinterpret_cast<voidFun>(fun<char>);
    call(std::make_shared<int>(33));


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