কীভাবে ওভারলোড করবেন std :: অদলবদল ()


115

std::swap()বাছাই এবং এমনকি অ্যাসাইনমেন্টের সময় অনেক স্ট্যান্ড পাত্রে (যেমন std::listএবং std::vector) ব্যবহার করে ।

তবে স্ট্যান্ডের বাস্তবায়নটি swap()খুব সাধারণীকরণ এবং কাস্টম ধরণের জন্য অকার্যকর।

এইভাবে std::swap()কাস্টম ধরণের নির্দিষ্ট প্রয়োগের মাধ্যমে ওভারলোডিংয়ের মাধ্যমে দক্ষতা অর্জন করা যায় । তবে আপনি কীভাবে এটি বাস্তবায়ন করতে পারেন যাতে এটি স্ট্যান্ড পাত্রে ব্যবহৃত হবে?


সম্পর্কিত তথ্য: en.cppreferences.com/w/cpp/concept/Swppable
ফারাপ

উত্তর:


135

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

class X
{
    // ...
    friend void swap(X& a, X& b)
    {
        using std::swap; // bring in swap for built-in types

        swap(a.base1, b.base1);
        swap(a.base2, b.base2);
        // ...
        swap(a.member1, b.member1);
        swap(a.member2, b.member2);
        // ...
    }
};

11
সি ++ 2003 এ এটি সর্বোত্তমভাবে নির্ধারিত। বেশিরভাগ বাস্তবায়নগুলি অদলবদল খুঁজতে ADL ব্যবহার করে তবে কোনও আদেশ দেওয়া হয় না, সুতরাং আপনি এটির উপর নির্ভর করতে পারবেন না। ওপি দ্বারা প্রদর্শিত কোনও নির্দিষ্ট কংক্রিটের জন্য আপনি স্টাডি :: অদলবদলকে বিশেষজ্ঞ করতে পারেন ; কেবলমাত্র সেই স্পেশালাইজেশনটি ব্যবহার হবে বলে আশা করবেন না, যেমন type ধরণের উত্সযুক্ত শ্রেণীর জন্য।
ডেভ আব্রাহামস

15
আমি অবাক হয়ে জানতে পারি যে বাস্তবায়নগুলি এখনও ঠিক মতো অদলবদল খুঁজে পেতে ADL ব্যবহার করে না। এটি কমিটিতে একটি পুরানো ইস্যু। আপনার বাস্তবায়ন যদি অদলবদলের জন্য ADL ব্যবহার না করে তবে একটি বাগ রিপোর্ট দাখিল করুন।
হাওয়ার্ড হিন্যান্ট

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

5
@ মোজ্জা314: এটি নির্ভর করে। একটি std::sortswap 'র উপাদান ADL ব্যবহার করে অ অনুসারী সি ++ 03 কিন্তু সি ++ 11 অনুসারী হয়। এছাড়াও, ক্লায়েন্টরা নন-আইডিয়োমেটিক কোড ব্যবহার করতে পারে এই তথ্যের ভিত্তিতে কেন উত্তর -1?
জোগ

4
@ কুরিয়াসগুয়ে: স্ট্যান্ডার্ড পড়া যদি স্ট্যান্ডার্ড পড়ার সাধারণ বিষয় ছিল, আপনি সঠিক হবেন :-)। দুর্ভাগ্যক্রমে, লেখকদের অভিপ্রায়টি গুরুত্বপূর্ণ। সুতরাং যদি আসল অভিপ্রায়টি ছিল যে ADL ব্যবহার করা যেতে পারে বা ব্যবহার করা উচিত, তবে এটি অপ্রস্তুত। যদি তা না হয় তবে এটি C ++ 0x এর জন্য কেবল একটি সাধারণ পুরানো পরিবর্তন,
ডেভ আব্রাহামস

70

মনোযোগ Mozza314

এখানে জেনেরিক std::algorithmকলিংয়ের প্রভাবগুলির সিমুলেশন রয়েছে std::swapএবং ব্যবহারকারীকে নাম স্থানের স্ট্যান্ডে তাদের অদলবদল সরবরাহ করে। এটি যেমন একটি পরীক্ষা, তাই এই সিমুলেশনটি namespace expপরিবর্তে ব্যবহার করে namespace std

// simulate <algorithm>

#include <cstdio>

namespace exp
{

    template <class T>
    void
    swap(T& x, T& y)
    {
        printf("generic exp::swap\n");
        T tmp = x;
        x = y;
        y = tmp;
    }

    template <class T>
    void algorithm(T* begin, T* end)
    {
        if (end-begin >= 2)
            exp::swap(begin[0], begin[1]);
    }

}

// simulate user code which includes <algorithm>

struct A
{
};

namespace exp
{
    void swap(A&, A&)
    {
        printf("exp::swap(A, A)\n");
    }

}

// exercise simulation

int main()
{
    A a[2];
    exp::algorithm(a, a+2);
}

আমার জন্য এটি প্রিন্ট করে:

generic exp::swap

যদি আপনার সংকলক কিছু আলাদা প্রিন্ট করে তবে এটি টেমপ্লেটগুলির জন্য "দ্বি-পর্যায়ের অনুসন্ধান" সঠিকভাবে প্রয়োগ করছে না।

আপনার সংকলক যদি (সি ++ 98/03/11 এর যে কোনও একটি) মেনে চলে, তবে এটি আমার দেখানো একই আউটপুট দেবে। এবং সেক্ষেত্রে আপনি যা হবেন ঠিক তা ঘটবে, ঘটবে। এবং আপনার swapনেমস্পেসে রেখে std( exp) এটি ঘটতে বাধা দেয় না।

ডেভ এবং আমি দুজনই কমিটির সদস্য এবং এক দশক ধরে মানকতার এই ক্ষেত্রটিতে কাজ করে যাচ্ছি (এবং সবসময় একে অপরের সাথে একমত নয়)। তবে এই বিষয়টি দীর্ঘদিন ধরে নিষ্পত্তি হয়েছে, এবং আমরা উভয়ই কীভাবে এটি নিষ্পত্তি হয়েছে সে বিষয়ে একমত। আপনার নিজের বিপদে এই অঞ্চলে ডেভের বিশেষজ্ঞ মতামত / উত্তর উপেক্ষা করুন।

এই সমস্যাটি C ++ 98 প্রকাশের পরে প্রকাশিত হয়েছিল। 2001 সালের শুরুতে ডেভ এবং আমি এই অঞ্চলটিতে কাজ শুরু করি । এবং এটি আধুনিক সমাধান:

// simulate <algorithm>

#include <cstdio>

namespace exp
{

    template <class T>
    void
    swap(T& x, T& y)
    {
        printf("generic exp::swap\n");
        T tmp = x;
        x = y;
        y = tmp;
    }

    template <class T>
    void algorithm(T* begin, T* end)
    {
        if (end-begin >= 2)
            swap(begin[0], begin[1]);
    }

}

// simulate user code which includes <algorithm>

struct A
{
};

void swap(A&, A&)
{
    printf("swap(A, A)\n");
}

// exercise simulation

int main()
{
    A a[2];
    exp::algorithm(a, a+2);
}

আউটপুট হল:

swap(A, A)

হালনাগাদ

একটি পর্যবেক্ষণ করা হয়েছে যে:

namespace exp
{    
    template <>
    void swap(A&, A&)
    {
        printf("exp::swap(A, A)\n");
    }

}

কাজ করে! তাহলে কেন এটি ব্যবহার করবেন না?

আপনার শ্রেণিবদ্ধ যে কেসটি বিবেচনা করুন A:

// simulate user code which includes <algorithm>

template <class T>
struct A
{
};

namespace exp
{

    template <class T>
    void swap(A<T>&, A<T>&)
    {
        printf("exp::swap(A, A)\n");
    }

}

// exercise simulation

int main()
{
    A<int> a[2];
    exp::algorithm(a, a+2);
}

এখন আর কাজ করে না। :-(

সুতরাং আপনি swapনেমস্পেস স্টাডিতে লাগাতে পারেন এবং এটি কাজ করতে পারেন। কিন্তু আপনি লাগাতে মনে রাখা প্রয়োজন হবে swapমধ্যে Aক্ষেত্রে জন্য এর নামস্থান আপনি একটি টেমপ্লেট আছে: A<T>। যেহেতু উভয় ক্ষেত্রেই যদি আপনি করা কাজ করবে swapমধ্যে Aএর নামস্থান, এটা (ও শিক্ষা দেয় অন্যদের কাছে) শুধু এটা করতে যে এক উপায় মাত্র মনে রাখা সহজ।


4
থ্যাঙ্কিউ আপনি বিস্তারিত উত্তরের জন্য। আমি এ সম্পর্কে পরিষ্কারভাবে কম জ্ঞাত এবং আসলে কীভাবে ওভারলোডিং এবং বিশেষায়িতকরণ বিভিন্ন আচরণ তৈরি করতে পারে তা নিয়ে ভাবছিলাম। তবে আমি অতিরিক্ত লোডিংয়ের পরামর্শ দিচ্ছি না তবে বিশেষীকরণ করছি। আমি যখন template <>আপনার প্রথম উদাহরণটি রাখি তখন আমি exp::swap(A, A)জিসিসি থেকে আউটপুট পাই । তাহলে, বিশেষায়িতকরণ কেন পছন্দ করবেন না?
ভোল্ট্রেভো

1
কি দারুন! এটা সত্যিই আলোকিত। আপনি অবশ্যই আমাকে বিশ্বাস করেছেন। আমি মনে করি আমি আপনার পরামর্শটি কিছুটা সংশোধন করব এবং ডেভ আব্রাহামস-এর মধ্যবর্তী শ্রেণির বন্ধু সিনট্যাক্সটি ব্যবহার করব (আরে আমি এটি অপারেটরের জন্য ব্যবহার করতে পারি << খুব! :-)), যদি না থাকে তবে তা এড়িয়ে যাওয়ার কোনও কারণ নেই (সংকলন ব্যতীত অন্য) আলাদাভাবে)। এছাড়াও, এর আলোকে, আপনার কি মনে using std::swapহয় "শিরোলেখ ফাইলগুলির অভ্যন্তরে বিবৃতি ব্যবহার না করা" নিয়মের ব্যতিক্রম? আসলে কেন using std::swapভিতরে <algorithm>? ুকিয়ে দেওয়া হচ্ছে না ? আমি মনে করি এটি মানুষের কোডের একটি ক্ষুদ্র সংখ্যালঘুটি ভেঙে দিতে পারে। সম্ভবত সমর্থন অবমূল্যায়ন এবং অবশেষে এটি করা?
ভোল্ট্রেভো

3
ইন-ক্লাস ফ্রেন্ড সিনট্যাক্স ঠিক থাকতে হবে। আমি using std::swapআপনার শিরোনামগুলির মধ্যে কার্যকারিতা সীমাবদ্ধ করার চেষ্টা করব । হ্যাঁ, swapপ্রায় একটি কীওয়ার্ড। তবে না, এটি বেশ কীওয়ার্ড নয়। সুতরাং আপনাকে যতক্ষণ না দরকার ততক্ষণ এটিকে সমস্ত নেমস্পেসে রফতানি না করা সেরা। swapঅনেক ভালো হয় operator==। সবচেয়ে বড় পার্থক্যটি হ'ল কেউই এমনকি operator==যোগ্য নেমস্পেস সিনট্যাক্সের সাথে কল করার কথাও ভাবেন না (এটি কেবল খুব কুশ্রী হবে)।
হাওয়ার্ড হিন্যান্ট

15
@ নীলকির্ক: আপনি জটিলতা হিসাবে যা দেখছেন তা হ'ল অনেকগুলি ভুল উত্তর। ডেভ আব্রাহামসের সঠিক উত্তর সম্পর্কে জটিল কিছু নেই: "অদলবদল ওভারলোডের সঠিক উপায়টি হ'ল আপনি যা বদলে যাচ্ছেন ঠিক একই নামস্থানে এটি লিখতে হবে, যাতে এটি যুক্তি-নির্ভর নির্ভরতা (এডিএল) এর মাধ্যমে পাওয়া যায়।"
হাওয়ার্ড হিন্যান্ট

2
@ কোডশট: দুঃখিত 1998 সাল থেকে ভেষজ এই বার্তাটি পাওয়ার চেষ্টা করছেন: getw.ca/publications/mill02.htm তিনি এই নিবন্ধে অদলবদলের কথা উল্লেখ করেন নি। তবে এটি হার্বের ইন্টারফেস নীতিমালার আরও একটি প্রয়োগ।
হাওয়ার্ড হিনান্ট

53

আপনাকে (সি ++ স্ট্যান্ডার্ড দ্বারা) এসডিডি :: অদলবদলের ওভারলোড করার অনুমতি নেই তবে আপনাকে বিশেষত স্ট্যান্ড নেমস্পেসে নিজের ধরণের টেমপ্লেট বিশেষায়িতকরণের অনুমতি দেওয়া হয়। যেমন

namespace std
{
    template<>
    void swap(my_type& lhs, my_type& rhs)
    {
       // ... blah
    }
}

তারপরে স্ট্যান্ড পাত্রে ব্যবহারগুলি (এবং অন্য কোথাও) সাধারণের পরিবর্তে আপনার বিশেষায়িতকরণটি বেছে নেবে।

এছাড়াও নোট করুন যে অদলবদলের একটি বেস শ্রেণীর বাস্তবায়ন সরবরাহ করা আপনার উত্পন্ন ধরণের জন্য যথেষ্ট ভাল নয়। যেমন যদি আপনার হয়

class Base
{
    // ... stuff ...
}
class Derived : public Base
{
    // ... stuff ...
}

namespace std
{
    template<>
    void swap(Base& lha, Base& rhs)
    {
       // ...
    }
}

এটি বেস ক্লাসগুলির জন্য কাজ করবে, তবে আপনি যদি দুটি উত্পন্ন বস্তু অদলবদল করার চেষ্টা করেন তবে এটি স্ট্যান্ডার্ড থেকে জেনেরিক সংস্করণ ব্যবহার করবে কারণ টেম্প্লেটেড অদলবদল একটি সঠিক মিল (এবং এটি কেবল আপনার উত্পন্ন বস্তুর অংশ 'ভিত্তি' অদলবদলের সমস্যা এড়াতে পারে) )।

দ্রষ্টব্য: আমি আমার শেষ উত্তর থেকে ভুল বিট অপসারণ করতে এটি আপডেট করেছি। ডি আহা! (ধন্যবাদ পুইজক এবং জ_আর্যান্ডম_হ্যাকার এটিকে নির্দেশ করার জন্য)


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

11
ডাউনভোটেড কারণ স্বাপটি কাস্টমাইজ করার সঠিক উপায়টি নিজের নিজের জায়গায় করা (যেমন ডেভ আব্রাহামস অন্য উত্তরে নির্দেশ করেছেন)।
হাওয়ার্ড হিন্যান্ট

2
ডাউনভোটিংয়ের জন্য আমার কারণগুলি হাওয়ার্ডের মতো
ডেভ আব্রাহামস

13
@ হাওয়ার্ডহিন্যান্ট, ডেভ আব্রাহামস: আমি একমত নই কোন ভিত্তিতে আপনি দাবি করেন যে আপনার বিকল্পটি "সঠিক" উপায়? মান হিসাবে puetzk উদ্ধৃত হিসাবে, এটি বিশেষভাবে অনুমোদিত। আমি এই ইস্যুতে নতুন থাকাকালীন আমি আপনার পক্ষে প্রচারিত পদ্ধতিটি সত্যিই পছন্দ করি না কারণ যদি আমি ফোকে সংজ্ঞায়িত করি এবং সেভাবে অদলবদল করি তবে আমার কোড ব্যবহার করা অন্য কেউ স্ট্যাড :: অদলবদল (ক, খ) বদলে ব্যবহার করতে পারে ( ক, খ) ফু-তে, যা নিঃশব্দে অদক্ষ ডিফল্ট সংস্করণ ব্যবহার করে।
ভোল্ট্রেভো

5
@ মোজ্জা ৩১৪: মন্তব্য ক্ষেত্রের স্থান এবং বিন্যাসের সীমাবদ্ধতা আমাকে আপনাকে পুরোপুরি জবাব দিতে দেয়নি। দয়া করে "মনোযোগ মোজ্জা314" শিরোনামের উত্তরটি জুড়ে দেখুন।
হাওয়ার্ড হিনান্ট

29

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

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

স্ট্যান্ড :: অদলবদলের একটি বিশেষায়নের মত দেখতে হবে:

namespace std
{
    template<>
    void swap(myspace::mytype& a, myspace::mytype& b) { ... }
}

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

একটা হল comp.lang.c উপর থ্রেড ++,। সংযত একটি সঙ্গে দীর্ঘ বিষয়ের dicussion। এর বেশিরভাগ অংশ আংশিক বিশেষজ্ঞের বিষয়ে, যদিও (বর্তমানে এটি করার কোনও ভাল উপায় নেই)।


7
এর জন্য (বা যে কোনও কিছুর জন্য) ফাংশন টেম্পলেট বিশেষায়নের ব্যবহার করা ভুল: এটি ওভারলোডগুলির সাথে খারাপ উপায়ে ইন্টারঅ্যাক্ট করে, যার মধ্যে অদলবদলের জন্য অনেকগুলি রয়েছে। উদাহরণস্বরূপ, আপনি যদি std :: ভেক্টর <mytype> & র জন্য নিয়মিত std :: swap বিশেষজ্ঞ করেন তবে আপনার বিশেষীকরণটি স্ট্যান্ডার্ডের ভেক্টর-নির্দিষ্ট অদলবদলের তুলনায় বেছে নেওয়া হবে না, কারণ ওভারলোড রেজোলিউশনের সময় বিশেষত্ব বিবেচনা করা হয় না।
ডেভ আব্রাহামস

4
মায়ার্স কার্যকর সি ++ 3 এড (আইটেম 25, পিপি 106-112) এও পরামর্শ দেয়।
jww

2
@ ডেভআব্রাহামস: আপনি যদি বিশেষজ্ঞ হন (সুস্পষ্ট টেম্পলেট যুক্তি ব্যতীত), আংশিক ক্রমকরণ এটি সংস্করণটির বিশেষীকরণ হিসাবে দেখাবেvector এবং এটি ব্যবহার করা হবে
ডেভিস হেরিং

1
@ ডেভিস হেরিং আসলে, না আপনি যখন আংশিক অর্ডারের কোনও ভূমিকা রাখেন না। সমস্যাটি এমন নয় যে আপনি একে একে কল করতে পারবেন না; অদলবদলের আপাত-কম-নির্দিষ্ট ওভারলোডগুলির উপস্থিতিতে এটি ঘটেছিল: ভ্যান্ডবক্স.আর
ডেভ আব্রাহামস

2
@ ডেভআব্রাহামস: স্পষ্টত বিশেষীকরণের একাধিকটির সাথে মেলে যখন আংশিক ক্রম বিশেষ করে ফাংশন টেম্পলেট নির্বাচন করা । আপনি যে ::swapওভারলোডটি যুক্ত করেছেন তার std::swapজন্য ওভারলোডের চেয়ে বেশি বিশেষায়িত vector, তাই এটি কলটি ক্যাপচার করে এবং পরবর্তীকালের কোনও বিশেষীকরণ প্রাসঙ্গিক নয়। আমি নিশ্চিত না যে এটি কীভাবে ব্যবহারিক সমস্যা (তবে আমি দাবিও করছি না যে এটি একটি ভাল ধারণা!)।
ডেভিস হেরিং 21
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.