লেখার বিভিন্ন উপায় আছে swap
, কিছু অন্যের চেয়ে ভাল। সময়ের সাথে সাথে, এটি একটি একক সংজ্ঞা সবচেয়ে ভাল কাজ করে দেখা গেছে। আসুন বিবেচনা করা যাক আমরা কীভাবে কোনও swap
ফাংশন লেখার বিষয়ে ভাবতে পারি ।
আমরা প্রথমে দেখতে পাচ্ছি যে ধারকগুলির মধ্যে std::vector<>
একক-যুক্তি সদস্যের ফাংশন রয়েছে swap
, যেমন:
struct vector
{
void swap(vector&) { /* swap members */ }
};
স্বাভাবিকভাবেই, তাহলে, আমাদের ক্লাসেরও উচিত, তাই না? সত্যিই ভাল না. স্ট্যান্ডার্ড লাইব্রেরিতে সব ধরণের অপ্রয়োজনীয় জিনিস রয়েছে এবং এর swap
মধ্যে অন্যতম সদস্য । কেন? এর উপর যান.
আমাদের যা করা উচিত তা হ'ল আধ্যাত্মিক কী এবং আমাদের শ্রেণিটি কী তা চিহ্নিত করা এটির সাথে কাজ করার জন্য কী প্রয়োজনএবং অদলবদলের ক্যানোনিকাল পদ্ধতিটি সহ std::swap
। এই কারণেই সদস্য ফাংশনগুলি কার্যকর নয়: সাধারণভাবে কীভাবে আমাদের জিনিসগুলি অদলবদল করা উচিত তা সেগুলি নয় এবং এর আচরণের কোনও ফলস্বরূপ নেই std::swap
।
ঠিক আছে, std::swap
কাজ করার জন্য আমাদের std::vector<>
একটি বিশেষত্ব প্রদান করা উচিত (এবং দেওয়া উচিত ছিল) std::swap
, তাই না?
namespace std
{
template <> // important! specialization in std is OK, overloading is UB
void swap(myclass&, myclass&)
{
// swap
}
}
ভাল এটি অবশ্যই এই ক্ষেত্রে কাজ করবে, তবে এটির একটি উদ্ভট সমস্যা আছে: ফাংশন বিশেষায়িত অংশগুলি আংশিক হতে পারে না। এটি হল, আমরা এটির সাথে টেমপ্লেট ক্লাস বিশেষায়িত করতে পারি না, কেবলমাত্র নির্দিষ্ট ইনস্ট্যান্টেশনগুলি:
namespace std
{
template <typename T>
void swap<T>(myclass<T>&, myclass<T>&) // error! no partial specialization
{
// swap
}
}
এই পদ্ধতিটি কিছু সময়ের জন্য কাজ করে তবে সমস্ত সময় নয়। আরও ভাল উপায় থাকতে হবে।
এখানে! আমরা একটি friend
ফাংশন ব্যবহার করতে পারি এবং এটি ADL এর মাধ্যমে খুঁজে পেতে পারি :
namespace xyz
{
struct myclass
{
friend void swap(myclass&, myclass&);
};
}
আমরা swap 'র কিছু করতে চান, তখন আমরা শরীক † std::swap
এবং তারপর একটি অযোগ্য কল করতে:
using std::swap; // allow use of std::swap...
swap(x, y); // ...but select overloads, first
// that is, if swap(x, y) finds a better match, via ADL, it
// will use that instead; otherwise it falls back to std::swap
কি friend
ফাংশন কি? এই অঞ্চলটিকে ঘিরে বিভ্রান্তি রয়েছে।
আগে সি ++ আদর্শায়িত করা হয়েছিল, friend
ফাংশন কিছু "বন্ধু নাম ইনজেকশন" বলা হয়, যেখানে কোড ভদ্র করেনি হিসাবে যদি যদি ফাংশন পার্শ্ববর্তী নামস্থান লেখা হয়েছে। উদাহরণস্বরূপ, এগুলি পূর্বমানের সমতুল্য ছিল:
struct foo
{
friend void bar()
{
// baz
}
};
// turned into, pre-standard:
struct foo
{
friend void bar();
};
void bar()
{
// baz
}
যাইহোক, যখন ADL আবিষ্কার করা হয়েছিল তখন এটি সরানো হয়েছিল। friend
ফাংশন তারপর পারে শুধুমাত্র ADL মাধ্যমে পাওয়া যাবে; আপনি যদি এটি একটি ফ্রি ফাংশন হিসাবে চান, এটি এটি হিসাবে ঘোষণা করা দরকার (এটি দেখুন , উদাহরণস্বরূপ)। তবে ল! একটা সমস্যা ছিল.
আপনি যদি কেবল ব্যবহার করেন তবে std::swap(x, y)
আপনার ওভারলোডটি কখনই পাওয়া যাবে না , কারণ আপনি স্পষ্টভাবে বলেছিলেন "দেখুন std
, আর কোথাও নেই"! এ কারণেই কিছু লোক দুটি ফাংশন লেখার পরামর্শ দিয়েছেন: একটি ফাংশন হিসাবে ADL এর মাধ্যমে পাওয়া যায় এবং অন্যটি স্পষ্টত std::
যোগ্যতাগুলি পরিচালনা করতে ।
তবে আমরা যেমন দেখেছি, এটি সব ক্ষেত্রেই কাজ করতে পারে না এবং আমরা কুৎসিত জগাখিচুড়ি দিয়ে শেষ করি। পরিবর্তে, অভিব্যক্তিগত অদলবদল অন্য পথে চলে গেছে: ক্লাসগুলির সরবরাহ করার জন্য এটি তৈরি করার পরিবর্তে, std::swap
তারা যোগ্য ব্যবহার না করেছে তা নিশ্চিত করার জন্য এটি অদলবদলের কাজ it'sswap
, ওপরের মতো । এবং এটি বেশ ভাল কাজ করার ঝোঁক দেয়, যতক্ষণ না লোকেরা এটি সম্পর্কে জানেন। তবে এর মধ্যে সমস্যাটি রয়েছে: অযোগ্য কলটি ব্যবহার করা দরকার u
এটি আরও সহজ করার জন্য, বুস্টের মতো কিছু লাইব্রেরি ফাংশন সরবরাহ করেছিল boost::swap
যা কেবলমাত্র একটি অযোগ্য কল করে swap
, এর সাথেstd::swap
এই ক্ষেত্রে সংশ্লিষ্ট নামস্থান হিসাবে। এটি জিনিসগুলিকে আবার সংহত করতে সহায়তা করে, তবে এটি এখনও একটি ঝাঁকুনি।
মনে রাখবেন যে সি ++ 11 এর আচরণে কোনও পরিবর্তন নেই std::swap
, যা আমি এবং অন্যরা ভুল করে ভেবেছিলাম কেস হবে। আপনি যদি এই দ্বারা বিট ছিল, এখানে পড়ুন ।
সংক্ষেপে: সদস্য ফাংশনটি কেবল গোলমাল, বিশেষীকরণটি কুরুচিপূর্ণ এবং অসম্পূর্ণ, তবে friend
ফাংশনটি সম্পূর্ণ এবং কাজ করে। আর তুমি অদলবদল যখন, হয় ব্যবহার boost::swap
অথবা একটি অযোগ্য swap
সঙ্গে std::swap
যুক্ত।
Forma অনানুষ্ঠানিকভাবে, কোনও নাম যুক্ত হয় যদি এটি কোনও ফাংশন কলের সময় বিবেচনা করা হয়। বিশদ জন্য, পড়ুন .43.4.2। এই ক্ষেত্রে, std::swap
সাধারণত বিবেচনা করা হয় না; তবে আমরা এটি সংযুক্ত করতে পারি (এটি অযোগ্য হিসাবে বিবেচিত ওভারলোডের সেটে যোগ করুন swap
), এটি সন্ধান করার অনুমতি দিয়ে।