c++ উনল কিভাবে `void_t` কাজ করে




সি++ বই (2)

// 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 ) বিদ্যমান থাকে, তাই যখন decltype( T::member ) বৈধ এবং দ্ব্যর্থহীন নয়। has_member<T , void> মন্তব্য হিসাবে রাষ্ট্রের জন্য।

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

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

আমি Cppcon14 এ ওয়াল্টার ব্রাউন এর কথোপকথনটি আধুনিক টেম্পলেট প্রোগ্রামিং ( পার্ট I , পার্ট II ) সম্পর্কে দেখেছি যেখানে তিনি তার void_t SFINAE টেকনিক উপস্থাপন করেছিলেন।

উদাহরণ:
সমস্ত টেমপ্লেট আর্গুমেন্টগুলি ভালভাবে গঠিত হলে 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 মূল্যায়ন
  • 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 > যুক্তি হিসাবে অকার্যকর সহ compiler has_member< B , class = void > খুঁজে বের করে
  • has_member< B > false_type মূল্যায়ন করে

http://ideone.com/HCTlBb

প্রশ্নাবলী:
1. এই সঠিক আমার বোঝার?
2. ওয়াল্টার ব্রাউন বলেছেন যে ডিফল্ট যুক্তিটি সঠিকভাবে একই রকম হতে হবে যেমনটি void_t জন্য কাজ করে। কেন যে? (আমি কেন এই ধরনের মেলে প্রয়োজন দেখতে না, কোন ডিফল্ট টাইপ কাজ করে না?)


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

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

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

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

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

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

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

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

টাইপ 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> । আর্গুমেন্টগুলি বিশেষীকরণের পরামিতিগুলির সাথে মেলে না এবং প্রাথমিক টেম্পলেটটি হ্রাসের হিসাবে নির্বাচিত হয়।

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

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

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





sfinae