c++ - উনল - সি++ বই




কীভাবে `void_t_ কাজ করে (2)

যখন আপনি has_member<A>::value লেখেন, has_member<A>::value নামটি সন্ধান করে এবং প্রাথমিক শ্রেণীর টেম্পলেটটি খুঁজে পায়, এটি হ'ল এই ঘোষণা:

template< class , class = void >
struct has_member;

(ওপিতে, এটি একটি সংজ্ঞা হিসাবে লেখা হয়েছে।)

টেম্পলেট আর্গুমেন্ট তালিকা <A> এই প্রাথমিক টেমপ্লেটের টেমপ্লেট প্যারামিটার তালিকার সাথে তুলনা করা হয়। যেহেতু প্রাথমিক টেম্পলেটটিতে দুটি প্যারামিটার রয়েছে তবে আপনি কেবল একটি সরবরাহ করেছেন, বাকি পরামিতিগুলি ডিফল্ট টেম্পলেট যুক্তির সাথে ডিফল্ট হয়েছে: void । এটি মনে হয় আপনি has_member<A, void>::value লিখেছেন।

এখন, টেমপ্লেট প্যারামিটার তালিকাটি has_member টেমপ্লেটের যে কোনও বিশেষত্বের সাথে তুলনা করা হয়। কোনও বিশেষায়নের সাথে মেলে না শুধুমাত্র, প্রাথমিক টেমপ্লেটের সংজ্ঞা একটি পতন-ব্যাক হিসাবে ব্যবহৃত হয়। সুতরাং আংশিক বিশেষত্ব বিবেচনায় নেওয়া হয়:

template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : true_type
{ };

সংকলক আংশিক বিশেষায়নের সংজ্ঞায়িত নিদর্শনগুলির সাথে A, void টেমপ্লেট আর্গুমেন্টগুলির সাথে মেলে চেষ্টা করে: T এবং void_t<..> একে একে। প্রথমত, টেমপ্লেট আর্গুমেন্ট ছাড় করা হয়। উপরের আংশিক বিশেষত্বটি এখনও টেমপ্লেট-পরামিতিগুলির সাথে একটি টেম্পলেট যা আর্গুমেন্ট দ্বারা "পূরণ করা" দরকার।

প্রথম প্যাটার্ন, T , সংকলকটিকে টেম্পলেট-প্যারামিটার T অনুমান করতে দেয়। এটি একটি তুচ্ছ ছাড়ের পরিমাণ, তবে T const& মতো একটি প্যাটার্ন বিবেচনা করুন T const& যেখানে আমরা এখনও T ছাড় করতে পারি। T এবং টেমপ্লেট আর্গুমেন্ট A , আমরা T কে A হতে অনুমান করি।

দ্বিতীয় প্যাটার্নে void_t< decltype( T::member ) > তে টেমপ্লেট-প্যারামিটার T এমন প্রসঙ্গে উপস্থিত হয় যেখানে এটি কোনও টেম্পলেট আর্গুমেন্ট থেকে বাদ দেওয়া যায় না। এই জন্য দুটি কারণ আছে:

  • decltype অভ্যন্তরে decltype স্পষ্টভাবে টেমপ্লেট আর্গুমেন্ট কর্তন থেকে বাদ দেওয়া হয়েছে। আমার ধারণা এটি এটি কারণ নির্বিচারে জটিল হতে পারে।

  • এমনকি যদি আমরা void_t< T > মতো void_t< T > ছাড়াই একটি প্যাটার্ন ব্যবহার করি, তবে T এর ছাড়ের সমাধানের নাম টেম্পলেটটিতে ঘটে। এটি হ'ল আমরা ওরফে টেমপ্লেটটি সমাধান করি এবং তারপরে ফলাফলের ধরণটি থেকে T টাইপটি কেটে নেওয়ার চেষ্টা করি। ফলস্বরূপ প্যাটার্নটি void , যা T উপর নির্ভর করে না এবং তাই আমাদের T জন্য নির্দিষ্ট ধরণের সন্ধান করতে দেয় না। এটি একটি ধ্রুবক ক্রিয়াকলাপটি উল্টানোর চেষ্টা করার গাণিতিক সমস্যার সাথে সমান (এই পদগুলির গাণিতিক অর্থে)।

টেমপ্লেট আর্গুমেন্ট ছাড়ের কাজ শেষ হয়েছে (*) , এখন ছাড়িয়ে যাওয়া টেম্পলেট আর্গুমেন্টগুলি প্রতিস্থাপন করা হবে। এটি এমন একটি বিশেষত্ব তৈরি করে যা দেখে মনে হয়:

template<>
struct has_member< A, void_t< decltype( A::member ) > > : true_type
{ };

টাইপটি void_t< decltype( A::member ) > > টাইপ void_t< decltype( A::member ) > > এখন মূল্যায়ন করা যায়। এটি প্রতিস্থাপনের পরে সু-গঠিত হয়, তাই কোনও প্রতিস্থাপনের ব্যর্থতা দেখা দেয় না। আমরা পেতে:

template<>
struct has_member<A, void> : true_type
{ };

এখন, আমরা এই বিশেষীকরণের টেমপ্লেট প্যারামিটার তালিকাটি মূল has_member<A>::value সরবরাহ করা টেম্পলেট আর্গুমেন্টের সাথে তুলনা করতে পারি। উভয় প্রকারের হুবহু মিলে যায় তাই এই আংশিক বিশেষত্বটি বেছে নেওয়া হয়েছে।

অন্যদিকে, যখন আমরা টেমপ্লেটটিকে এই হিসাবে সংজ্ঞায়িত করি:

template< class , class = int > // <-- int here instead of void
struct has_member : false_type
{ };

template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : true_type
{ };

আমরা একই বিশেষায়নের সাথে শেষ করি:

template<>
struct has_member<A, void> : true_type
{ };

তবে has_member<A>::value জন্য আমাদের টেমপ্লেট আর্গুমেন্টের তালিকাটি এখন হ'ল <A, int> has_member<A>::value <A, int> । যুক্তি বিশেষায়নের প্যারামিটারগুলির সাথে মেলে না এবং প্রাথমিক টেম্পলেটটি ফ্যাল-ব্যাক হিসাবে বেছে নেওয়া হয়েছে।

(*) স্ট্যান্ডার্ড, আইএমএইচও বিভ্রান্তিমূলকভাবে প্রতিস্থাপন প্রক্রিয়া এবং টেমপ্লেট আর্গুমেন্ট ছাড়ের প্রক্রিয়াতে স্পষ্টভাবে নির্দিষ্ট টেম্পলেট আর্গুমেন্টগুলির মিলে অন্তর্ভুক্ত। উদাহরণস্বরূপ (পোস্ট- N4296) [temp.class.spec.match] / 2:

আংশিক বিশেষীকরণ একটি প্রদত্ত আসল টেম্পলেট আর্গুমেন্ট তালিকার সাথে মেলে যদি আংশিক বিশেষায়নের টেম্পলেট আর্গুমেন্টগুলি প্রকৃত টেম্পলেট আর্গুমেন্ট তালিকা থেকে বাদ দেওয়া যায়।

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

আমি আধুনিক টেম্পলেট প্রোগ্রামিং ( দ্বিতীয় খণ্ড, দ্বিতীয় ) সম্পর্কে সিপ্পকন 14 এ ওয়াল্টার ব্রাউনয়ের বক্তব্যটি দেখেছি যেখানে তিনি তার void_t SFINAE কৌশল উপস্থাপন করেছেন।

উদাহরণ:
একটি সাধারণ ভেরিয়েবল টেম্পলেট দেওয়া হয়েছে যা সমস্ত টেম্পলেট আর্গুমেন্ট ভালভাবে গঠন void থাকলে void মূল্যায়ন করে:

template< class ... > using void_t = void;

এবং নিম্নলিখিত বৈশিষ্ট্য যা সদস্য নামে পরিচিত সদস্যের অস্তিত্বের জন্য যাচাই করে:

template< class , class = void >
struct has_member : std::false_type
{ };

// specialized as has_member< T , void > or discarded (sfinae)
template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : std::true_type
{ };

কেন এবং কীভাবে এটি কাজ করে তা বোঝার চেষ্টা করেছি। অতএব একটি ছোট উদাহরণ:

class A {
public:
    int member;
};

class B {
};

static_assert( has_member< A >::value , "A" );
static_assert( has_member< B >::value , "B" );

1. has_member< A >

  • has_member< A , void_t< decltype( A::member ) > >
    • A::member উপস্থিত
    • decltype( A::member ) সুগঠিত
    • void_t<> বৈধ এবং void_t<> করার জন্য মূল্যায়ন করে
  • has_member< A , void > এবং তাই এটি বিশেষায়িত টেম্পলেটটি চয়ন করে
  • has_member< T , void > এবং true_type মূল্যায়ন করে

2. has_member< B >

  • has_member< B , void_t< decltype( B::member ) > >
    • B::member অস্তিত্ব নেই
    • decltype( B::member ) দূষিত এবং নিঃশব্দে ব্যর্থ হয় (sfinae)
    • has_member< B , expression-sfinae > তাই এই টেমপ্লেটটি বাতিল করা হয়েছে
  • has_member< B , class = void > ডিফল্ট আর্গুমেন্ট হিসাবে has_member< B , class = void > করে
  • has_member< B > false_type মূল্যায়ন করে

http://ideone.com/HCTlBb

প্রশ্নাবলী:
১. আমার এই বিষয়টি কি সঠিক?
২. ওয়াল্টার ব্রাউন বলেছেন যে ডিফল্ট আর্গুমেন্টটি কাজ করার জন্য void_t ব্যবহৃত void_t মতো একই ধরণের হতে হবে। তা কেন? (আমি দেখতে পাচ্ছি না কেন এই ধরণেরগুলি মেলানো দরকার, কেবল কোনও ডিফল্ট ধরণের কাজটি করে না?)


// specialized as has_member< T , void > or discarded (sfinae)
template<class T>
struct has_member<T , void_t<decltype(T::member)>> : true_type
{ };

উপরোক্ত বিশেষজ্ঞকরণটি তখনই বিদ্যমান যখন এটি ভালভাবে গঠিত হয়, সুতরাং যখন decltype( T::member ) বৈধ হয় এবং অস্পষ্ট নয়। has_member<T , void> মন্তব্যে রাষ্ট্র হিসাবে has_member<T , void>

যখন আপনি has_member<A> , এটি ডিফল্ট টেম্পলেট আর্গুমেন্টের কারণে has_member<A, void>

এবং আমাদের কাছে has_member<A, void> (তাই true_type থেকে উত্তরাধিকারী) এর জন্য has_member<B, void> তবে আমাদের কাছে has_member<B, void> জন্য has_member<B, void> (সুতরাং আমরা ডিফল্ট সংজ্ঞাটি ব্যবহার করি: false_type থেকে উত্তরাধিকারী)





sfinae