কীভাবে `void_t_ কাজ করে


149

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

উদাহরণ:
একটি সাধারণ ভেরিয়েবল টেম্পলেট দেওয়া হয়েছে যা মূল্যায়ন করে 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 >ডিফল্ট আর্গুমেন্ট হিসাবে শূন্যের সাথে খুঁজে পায়
  • has_member< B > মূল্যায়ন false_type

http://ideone.com/HCTlBb

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


6
এ্যাড 2) কল্পনা করুন স্ট্যাটিক জাহির হিসেবে লেখা হয়েছিল: has_member<A,int>::value। তারপরে, আংশিক বিশেষায়নের সাথে যা মূল্যায়ন করে has_member<A,void>তা মেলে না। অতএব, এটি has_member<A,void>::valueসিনট্যাকটিক চিনির সাথে হওয়া উচিত , টাইপের একটি ডিফল্ট যুক্তি void
ডিসি

1
@ ডিপ ধন্যবাদ, আমি এটি সম্পাদনা করব। মিঃ, আমি এখনও has_member< T , class = void >ডিফল্ট করার প্রয়োজন দেখছি না void। এই বৈশিষ্ট্যটি ধরে নিলাম যে কোনও সময়ে কেবল 1 টি টেমপ্লেট আর্গুমেন্টের সাথে ব্যবহৃত হবে, তবে ডিফল্ট আর্গুমেন্টটি কোনও ধরণের হতে পারে?
নির্লিপ্তি

আকর্ষণীয় প্রশ্ন।
এশোফার

2
দ্রষ্টব্য যে এই প্রস্তাবনায় ওপেন-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf , ওয়াল্টার পরিবর্তিত template <class, class = void>হয়েছে template <class, class = void_t<>>। সুতরাং এখন আমরা void_tওরফে টেমপ্লেট প্রয়োগের সাথে যা কিছু করতে চাই তা করতে
নির্দ্বিধায়

উত্তর:


133

1. প্রাথমিক ক্লাস টেম্পলেট

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

template< class , class = void >
struct has_member;

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

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

2. বিশেষায়িত ক্লাস টেম্পলেট

এখন , টেমপ্লেটের প্যারামিটার তালিকাটি টেমপ্লেটের কোনও বিশেষত্বের সাথে তুলনা করা হয়েছে 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। প্যাটার্ন Tএবং টেমপ্লেট আর্গুমেন্টের জন্য A, আমরা Tহতে অনুমিত করি A

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

এই জন্য দুটি কারণ আছে:

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

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

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

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
{ };

3. পছন্দ

এখন , আমরা এই স্পেশালাইজেশনের টেমপ্লেট প্যারামিটার তালিকাটি মূল সরবরাহিত টেম্পলেট আর্গুমেন্টের সাথে তুলনা করতে পারি 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> । যুক্তি বিশেষায়নের প্যারামিটারগুলির সাথে মেলে না এবং প্রাথমিক টেম্পলেটটি ফ্যাল-ব্যাক হিসাবে বেছে নেওয়া হয়েছে।


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

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

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


3
ধন্যবাদ! আমি এটি বারবার পড়েছি এবং টেমপ্লেট আর্গুমেন্ট ছাড়াই ঠিক কীভাবে কাজ করে এবং চূড়ান্ত টেমপ্লেটের জন্য সংকলকটি কী চয়ন করে তা এই মুহূর্তে সঠিক নয় সে সম্পর্কে আমার চিন্তাভাবনা অনুমান করি।
সংবেদনহীনতা

1
@ জোহানেস শ্যাব-লিটব ধন্যবাদ! যদিও এটি কিছুটা হতাশাজনক। কোনও বিশেষায়নের সাথে কোনও টেম্পলেট যুক্তির সাথে ম্যাচ করার সত্যিই কোনও নিয়ম নেই? এমনকি স্পষ্ট বিশেষায়নের জন্যও নয়?
ডিসি

2
ডাব্লু / আর / টি ডিফল্ট টেম্পলেট আর্গুমেন্ট, ওপেন- std.org/jtc1/sc22/wg21/docs/cwg_active.html#2008
টিসি

1
@dyp কয়েক সপ্তাহ পরে এবং এই সম্পর্কে প্রচুর পড়া এবং এই স্নিপেটের একটি ইঙ্গিত সহ আমার মনে হয় আমি কীভাবে এটি কাজ করে তা বুঝতে শুরু করি। আপনার ব্যাখ্যা পড়া থেকে আমার আরও জ্ঞান পড়তে তোলে, ধন্যবাদ!
নির্বিকার

1
আমি যুক্ত করতে চেয়েছিলাম যে প্রাথমিক টেমপ্লেটটি মূল কী ছিল (
কোডগুলিতে

18
// 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<A>, এটা হয়has_member<A, void> ডিফল্ট টেম্পলেট যুক্তির কারণে।

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

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