`Is_base_of` কীভাবে কাজ করে?


118

নিম্নলিখিত কোডটি কীভাবে কাজ করে?

typedef char (&yes)[1];
typedef char (&no)[2];

template <typename B, typename D>
struct Host
{
  operator B*() const;
  operator D*();
};

template <typename B, typename D>
struct is_base_of
{
  template <typename T> 
  static yes check(D*, T);
  static no check(B*, int);

  static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes);
};

//Test sample
class Base {};
class Derived : private Base {};

//Expression is true.
int test[is_base_of<Base,Derived>::value && !is_base_of<Derived,Base>::value];
  1. নোট যে Bব্যক্তিগত বেস। কিভাবে কাজ করে?

  2. নোট যে operator B*()কনস্ট্যান্ট। এটা কেন গুরুত্বপূর্ণ?

  3. এর template<typename T> static yes check(D*, T);চেয়ে ভাল কেন static yes check(B*, int);?

দ্রষ্টব্য : এটির সংস্করণ হ্রাস করা হয়েছে (ম্যাক্রোগুলি সরানো হয়েছে) boost::is_base_of। এবং এটি সংকলক বিস্তৃত উপর কাজ করে।


4
টেমপ্লেট প্যারামিটার এবং সত্য শ্রেণির নামের জন্য একই পরিচয়কারক ব্যবহার করা আপনার পক্ষে খুব বিভ্রান্তিকর ...
ম্যাথিউ এম।

1
@ ম্যাথিউ এম।, আমি এটি সংশোধন করার বিষয়টি নিজের উপর নিয়েছি :)
ক্যারিল ভি লিয়াডভিনস্কি

2
কিছু সময় আগে আমি এর বিকল্প বাস্তবায়ন লিখেছিলাম is_base_of: ideone.com/T0C1V যদিও এটি পুরানো জিসিসি সংস্করণগুলির সাথে কাজ করে না (জিসিসি 4.3 ভাল কাজ করে)।
জোহানেস স্কাউব -

3
ঠিক আছে, আমি হাঁটতে যাচ্ছি
জোকুন

2
এই বাস্তবায়নটি সঠিক নয়। is_base_of<Base,Base>::valueহওয়া উচিত true; এই ফিরে false
চেঙ্গিজ

উত্তর:


109

তারা যদি সম্পর্কিত হয়

আসুন এক মুহুর্তের জন্য ধরে নেওয়া যাক Bএটি আসলে একটি ভিত্তি D। তারপরে কল করার জন্য check, উভয় সংস্করণ কার্যকরযোগ্য কারণ Hostরূপান্তরিত হতে পারে D* এবং B* । এটা একটা ব্যবহারকারী সংজ্ঞায়িত রূপান্তর ক্রম হিসাবে বর্ণনা করেন 13.3.3.1.2থেকে Host<B, D>থেকে D*এবং B*যথাক্রমে। শ্রেণি রূপান্তর করতে পারে এমন রূপান্তর ফাংশনগুলি সন্ধানের জন্য, নিম্নলিখিত প্রার্থীর checkফাংশন অনুসারে প্রথম ফাংশনের জন্য সংশ্লেষ করা হয়13.3.1.5/1

D* (Host<B, D>&)

প্রথম রূপান্তর ফাংশনটি কোনও প্রার্থী নয়, কারণ এতে B*রূপান্তর করা যায় না D*

দ্বিতীয় কার্যের জন্য, নিম্নলিখিত প্রার্থীরা উপস্থিত আছেন:

B* (Host<B, D> const&)
D* (Host<B, D>&)

এই দুটি রূপান্তর ফাংশন প্রার্থী যারা হোস্ট অবজেক্ট গ্রহণ করে। প্রথমটি এটি কনস্ট্যান্ড রেফারেন্স দ্বারা গ্রহণ করে, এবং দ্বিতীয়টি তা গ্রহণ করে না। সুতরাং দ্বিতীয়টি নন-কনস্ট্যান্ট *thisঅবজেক্টের জন্য আরও ভাল ম্যাচ ( অন্তর্নিহিত অবজেক্ট আর্গুমেন্ট ) দ্বারা 13.3.3.2/3b1sb4এবং B*দ্বিতীয় checkফাংশনে রূপান্তর করতে ব্যবহৃত হয় ।

আপনি যদি কনস্টেন্টটি সরিয়ে ফেলেন তবে আমাদের নীচের প্রার্থীরা থাকবেন

B* (Host<B, D>&)
D* (Host<B, D>&)

এর অর্থ হ'ল আমরা আর দৃ const়তার সাথে নির্বাচন করতে পারি না। একটি সাধারণ ওভারলোড রেজোলিউশন দৃশ্যে, কলটি এখন অস্পষ্ট হবে কারণ সাধারণত রিটার্নের ধরণটি ওভারলোড রেজোলিউশনে অংশ নেয় না। রূপান্তর ফাংশনগুলির জন্য, তবে একটি পিছনের কাজ রয়েছে। দুটি রূপান্তর ফাংশন যদি সমানভাবে ভাল হয় তবে তার মধ্যে ফেরতের ধরণটি সিদ্ধান্ত নেয় যে অনুযায়ী কে সেরা 13.3.3/1। সুতরাং, আপনি যদি কনটটি অপসারণ করেন, তবে প্রথমটি নেওয়া হবে, কারণ তার চেয়ে B*ভাল রূপান্তরিত হয় ।B*D*B*

এখন কোন ব্যবহারকারী সংজ্ঞায়িত রূপান্তর ক্রম ভাল? দ্বিতীয় বা প্রথম চেক ফাংশনটির জন্য একটি? নিয়মটি হল যে ব্যবহারকারীর সংজ্ঞায়িত রূপান্তর সিকোয়েন্সগুলি কেবল তখনই তুলনা করা যেতে পারে যদি তারা একই রূপান্তর ফাংশন বা কনস্ট্রাক্টর অনুসারে ব্যবহার করে 13.3.3.2/3b2। ঠিক এখানে ঘটনাটি: উভয়ই দ্বিতীয় রূপান্তর ফাংশনটি ব্যবহার করে। লক্ষ করুন যে এইভাবে কনস্টটিপটি গুরুত্বপূর্ণ কারণ এটি কম্পাইলারকে দ্বিতীয় রূপান্তর ফাংশন নিতে বাধ্য করে।

যেহেতু আমরা তাদের তুলনা করতে পারি - কোনটি ভাল? নিয়মটি হ'ল রূপান্তর ফাংশনের রিটার্ন টাইপ থেকে গন্তব্য প্রকারের (আবার দ্বারা 13.3.3.2/3b2) জিতে আরও ভাল রূপান্তর । এই ক্ষেত্রে, তুলনায় D*ভাল রূপান্তর । এইভাবে প্রথম ফাংশনটি নির্বাচিত হয় এবং আমরা উত্তরাধিকারকে স্বীকৃতি দেব!D*B*

লক্ষ করুন যে, যেহেতু আমরা করা প্রয়োজন কখনোই আসলে একটি বেস বর্গ রূপান্তর, আমরা যার ফলে চিনতে পারে ব্যক্তিগত উত্তরাধিকার কারণ কিনা আমরা একটি থেকে রূপান্তর করতে পারেন D*একটি থেকে B*অনুযায়ী উত্তরাধিকার আকারে উপর নির্ভরশীল নয়4.10/3

তারা সম্পর্কিত না হলে

এখন ধরা যাক তারা উত্তরাধিকারসূত্রে সম্পর্কিত নয়। সুতরাং প্রথম ফাংশনের জন্য আমাদের নিম্নোক্ত প্রার্থী রয়েছে

D* (Host<B, D>&) 

এবং দ্বিতীয় জন্য আমাদের এখন অন্য সেট আছে

B* (Host<B, D> const&)

যেহেতু আমরা উত্তরাধিকারের সম্পর্ক না পেয়ে আমরা রূপান্তর D*করতে পারি না B*, তাই এখন আমরা দুটি ব্যবহারকারীর সংজ্ঞায়িত রূপান্তর ক্রমের মধ্যে কোনও সাধারণ রূপান্তর ফাংশন নেই! প্রথম ফাংশনটি একটি টেমপ্লেট এই বিষয়টির জন্য না হলে আমরা অস্পষ্ট হয়ে উঠব । টেমপ্লেট যখন একটি অ-টেমপ্লেট ফাংশন যা সমানভাবে ভাল অনুযায়ী সেখানে দ্বিতীয় পছন্দ 13.3.3/1। সুতরাং, আমরা অ টেমপ্লেট ফাংশন (দ্বিতীয়) নির্বাচন করুন এবং আমরা স্বীকার মধ্যে কোন উত্তরাধিকার নেই Bএবং D!


2
আহ! আন্দ্রেয়াসের অনুচ্ছেদটি ঠিকঠাক ছিল, খুব খারাপ সে এইরকম উত্তর দেয়নি :) আপনার সময়ের জন্য ধন্যবাদ, আমি আশা করি আমি এটি পছন্দ করতে পারি।
ম্যাথিউ এম।

2
এটি আমার প্রিয় উত্তর হতে চলেছে ... একটি প্রশ্ন: আপনি কি পুরো সি ++ স্ট্যান্ডার্ডটি পড়েছেন বা আপনি কেবল সি ++ কমিটিতে কাজ করছেন ?? অভিনন্দন!
মার্কো এ

4
সি কাজ @DavidKernin ++, কমিটির স্বয়ংক্রিয়ভাবে আপনি কি জানেন কিভাবে সি ++ কাজ :) আপনি স্পষ্টভাবে স্ট্যান্ডার্ড যে বিস্তারিত জানতে প্রয়োজন হয়, যা আমি করেছি অংশ পড়তে তাই দেখা যায় না।
এগুলি

1
@ আসরস্কোর_ডি ন্যায়সঙ্গতভাবে, স্পেক স্ট্যান্ড :: বৈশিষ্ট্যগুলিকে কিছু সংকলক যাদু ব্যবহার করতে নিষেধ করে না যাতে মানক গ্রন্থাগার প্রয়োগকারীরা তাদের পছন্দমতো ব্যবহার করতে পারেন । তারা টেমপ্লেট অ্যাক্রোব্যাটিক্স এড়াতে পারবেন যা সময় এবং মেমরির সংকলনকে দ্রুতগতিতে সহায়তা করে। ইন্টারফেসটি দেখতে দেখতে এমনকি সত্য std::is_base_of<...>। সবই হুডের নিচে।
জোহানেস স্কাউব -

2
অবশ্যই, সাধারণ লাইব্রেরিগুলিতে এটি boost::ব্যবহারের আগে নিশ্চিত হওয়া দরকার যে এগুলি অন্তর্নিহিত রয়েছে। সংকলকের সাহায্য ছাড়াই জিনিসগুলি বাস্তবায়নের জন্য তাদের মধ্যে
একধরণের

24

আসুন পদক্ষেপগুলি দেখে এটি কীভাবে কাজ করে তা কার্যকর করা যাক।

sizeof(check(Host<B,D>(), int()))অংশ দিয়ে শুরু করুন । সংকলকটি তাড়াতাড়ি দেখতে পাবে যে check(...)এটি একটি ফাংশন কল এক্সপ্রেশন, সুতরাং এটির জন্য ওভারলোড রেজোলিউশনটি করা দরকার check। দুটি প্রার্থী ওভারলোড উপলব্ধ, template <typename T> yes check(D*, T);এবং no check(B*, int);। প্রথমটি যদি বেছে নেওয়া হয় তবে আপনি পাবেন sizeof(yes), অন্যথায়sizeof(no)

এর পরে, ওভারলোড রেজোলিউশনটি দেখি। প্রথম ওভারলোডটি একটি টেম্পলেট ইনস্ট্যান্টেশন check<int> (D*, T=int)এবং দ্বিতীয় প্রার্থী check(B*, int)। প্রকৃত যুক্তিগুলি হ'ল Host<B,D>এবং int()। দ্বিতীয় প্যারামিটার স্পষ্টভাবে তাদের পার্থক্য করে না; এটি কেবলমাত্র প্রথম ওভারলোডকে একটি টেম্পলেট তৈরি করতে পরিবেশন করেছে। আমরা পরে দেখব কেন টেম্পলেট অংশটি প্রাসঙ্গিক।

এখন রূপান্তর ক্রমগুলি প্রয়োজন যা দেখুন। প্রথম ওভারলোডের জন্য, আমাদের রয়েছে Host<B,D>::operator D*- একটি ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর। দ্বিতীয়টির জন্য, ওভারলোডটি আরও জটিল। আমাদের একটি বি * প্রয়োজন, তবে সম্ভবত দুটি রূপান্তর ক্রম রয়েছে। এক মাধ্যমে হয় Host<B,D>::operator B*() const। যদি (এবং কেবলমাত্র) বি এবং ডি উত্তরাধিকার অনুসারে সম্পর্কিত হয় তবে রূপান্তর ক্রম Host<B,D>::operator D*()+ D*->B*উপস্থিত থাকবে। এখন ধরে নিন ডি আসলেই বি থেকে উত্তরাধিকার সূত্রে দুটি রূপান্তর ক্রম Host<B,D> -> Host<B,D> const -> operator B* const -> B*এবং Host<B,D> -> operator D* -> D* -> B*

সুতরাং, সম্পর্কিত বি এবং ডি সম্পর্কিত ক্ষেত্রে no check(<Host<B,D>(), int())দ্বিধাগ্রস্ত হবে। ফলস্বরূপ, টেম্প্লেটেড yes check<int>(D*, int)চয়ন করা হয়। যাইহোক, ডি যদি বি এর উত্তরাধিকার সূত্রে না পায় তবে no check(<Host<B,D>(), int())দ্বিপাক্ষিক নয়। এই মুহুর্তে, সংক্ষিপ্ততম রূপান্তর ক্রমের ভিত্তিতে ওভারলোড রেজোলিউশনটি ঘটতে পারে না। যাইহোক, সমান রূপান্তর ক্রম দেওয়া, ওভারলোড রেজোলিউশন নন-টেম্পলেট ফাংশনগুলি পছন্দ করে no check(B*, int)

আপনি এখন দেখেন যে উত্তরাধিকারটি ব্যক্তিগত তা কেন গুরুত্বপূর্ণ নয়: সেই সম্পর্কটি no check(Host<B,D>(), int())অ্যাক্সেস চেক হওয়ার আগেই ওভারলোড রেজোলিউশন থেকে সরিয়ে দেয় । এবং আপনি এটিও দেখতে পাবেন যে কেন operator B* constঅবশ্যই দৃ .় হতে হবে: অন্যথায় Host<B,D> -> Host<B,D> constপদক্ষেপের দরকার নেই, দ্বিপাক্ষিকতা নেই এবং no check(B*, int)সর্বদা বেছে নেওয়া হবে।


আপনার ব্যাখ্যা উপস্থিতির জন্য অ্যাকাউন্ট করে না const। যদি আপনার উত্তরটি সত্য হয় তবে কোনও constপ্রয়োজন নেই। কিন্তু এটি সত্যি না। সরান constএবং কৌশল কাজ করবে না not
আলেক্সি মালিস্তভ 26'10

বিন্যাস ব্যতীত দুটি রূপান্তর সিকোয়েন্স no check(B*, int)আর অস্পষ্ট নয়।
এমসাল্টাররা 26'10

আপনি যদি কেবল ছেড়ে যান no check(B*, int), তবে সম্পর্কিত Bএবং এর জন্য D, এটি অস্পষ্ট নয়। সংকলকটি দ্ব্যর্থহীনভাবে operator D*()রূপান্তর সম্পাদন করতে পছন্দ করবে কারণ এতে কোনও কনস্ট নেই। বরং বিপরীত দিকে একটি বিট: আপনি যদি অপসারণ const, আপনি দ্ব্যর্থতার কিছু অর্থে পরিচয় করিয়ে, কিন্তু যা সত্য যে দ্বারা সমাধান করা operator B*()একটি উচ্চতর রিটার্ন টাইপ যা একটি পয়েন্টার রূপান্তর দরকার নেই উপলব্ধ B*মত D*আছে।
জোহানেস স্কাউব -

প্রকৃতপক্ষে এটি বিন্দু: অস্থায়ী B*থেকে একটি পেতে দুটি ভিন্ন রূপান্তর ক্রমের মধ্যে অস্পষ্টতা <Host<B,D>()
MSalters

এটি একটি ভাল উত্তর। ধন্যবাদ! সুতরাং, যেমন আমি বুঝতে পেরেছি, যদি একটি ফাংশনটি আরও ভাল, তবে অস্পষ্ট, তবে অন্য ফাংশনটি বেছে নেওয়া হয়?
ব্যবহারকারী 1289

4

privateবিট সম্পূর্ণভাবে দ্বারা উপেক্ষা করা হয় is_base_ofজমিদার রেজল্যুশন অভিগম্যতা চেক সামনে ঘটে কারণ।

আপনি এটি সহজভাবে যাচাই করতে পারেন:

class Foo
{
public:
  void bar(int);
private:
  void bar(double);
};

int main(int argc, char* argv[])
{
  Foo foo;
  double d = 0.3;
  foo.bar(d);       // Compiler error, cannot access private member function
}

এখানে একই কথা প্রযোজ্য, Bএকটি বেসরকারী বেস চেকটি হওয়া থেকে বাধা দেয় না, এটি কেবল রূপান্তরকে আটকাতে পারে, তবে আমরা কখনই প্রকৃত রূপান্তর চাই না;)


প্রকার, রকম. কোনও বেস রূপান্তর মোটেই সম্পাদিত হয় না। hostনির্বিচারে রূপান্তরিত হয় D*বা B*অমূল্য অভিব্যক্তিতে। কিছু কারণে, কিছু শর্তের অধীনে D*ভাল B*
পোটোসওয়টার

আমি মনে করি উত্তরটি 13.3.1.1.2 এ রয়েছে তবে আমি এখনও বিশদগুলি ছড়িয়ে দিতে পারি না :)
আন্দ্রেয়াস ব্রিন্ক

আমার উত্তরটি কেবল "ব্যক্তিগত এমনকি কেন কাজ করে" অংশটি ব্যাখ্যা করে, সেলিবিটজের উত্তর অবশ্যই আরও সম্পূর্ণ তবে আমি মামলাগুলির উপর নির্ভর করে পূর্ণ রেজোলিউশন প্রক্রিয়ার সুস্পষ্ট ব্যাখ্যাটির জন্য অধীর আগ্রহে অপেক্ষা করছি।
ম্যাথিউ এম।

2

এটির সম্ভবত আংশিক অর্ডারিং রিট ওভারলোড রেজোলিউশনের সাথে কিছু করার আছে। ডি * বি থেকে আরও বিশেষজ্ঞ হয় যদি ডি বি থেকে উদ্ভূত হয় in

সঠিক বিবরণ বরং জটিল। আপনাকে বিভিন্ন ওভারলোড রেজোলিউশন নিয়মের নজিরগুলি বের করতে হবে। আংশিক ক্রম এক। দৈর্ঘ্য / ধরণের রূপান্তর ক্রমগুলি অন্য এক another অবশেষে, যদি দুটি কার্যক্ষম ফাংশনকে সমানভাবে ভাল মনে করা হয়, তবে ফাংশন টেম্পলেটগুলির চেয়ে অ-টেম্পলেটগুলি বেছে নেওয়া হয়।

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

উত্তরাধিকার সূচনাকালীন হিসাবে: কোডটি কখনই ডি * থেকে বি * তে রূপান্তর চায় না যার জন্য সর্বজনীন উত্তরাধিকার প্রয়োজন।


আমি মনে করি এটি এরকমই কিছু, আমি মনে করি এটি বাস্তবায়ন সম্পর্কে উত্সাহ সংরক্ষণাগার সম্পর্কে একটি বিস্তৃত আলোচনা দেখেছি is_base_ofএবং এটি নিশ্চিত করতে অবদানকারীরা যে লুপগুলি পেরেছিলেন।
ম্যাথিউ এম।

The exact details are rather complicated- এটাই আসল কথা. দয়া করে ব্যাখ্যা করুন. আমি জানতে চাই না।
আলেক্সি মালিস্তভ

@ অ্যালেক্সা: ঠিক আছে, আমি ভেবেছিলাম আপনাকে সঠিক দিকের দিকে দেখিয়েছি। এই ক্ষেত্রে বিভিন্ন ওভারলোড রেজোলিউশন বিধি কীভাবে ইন্টারঅ্যাক্ট করে তা পরীক্ষা করে দেখুন। এই ওভারলোডিং কেসটির সমাধানের ক্ষেত্রে বি থেকে ডি নেওয়া এবং বি থেকে প্রাপ্ত ডি এর মধ্যে একমাত্র পার্থক্য হ'ল আংশিক আদেশের নিয়ম। ওভারলোড রেজোলিউশনটি C ++ স্ট্যান্ডার্ডের 1313 এ বর্ণিত হয়েছে। আপনি নিখরচায়
বিক্রয়বিটজে

ওভারলোড রেজোলিউশন সেই খসড়াটিতে 16 পৃষ্ঠাগুলি বিস্তৃত। আমার অনুমান, যদি এই মামলার জন্য আপনার যদি সত্যিকারের নিয়মগুলি এবং তাদের মধ্যে মিথস্ক্রিয়া বুঝতে হয় তবে আপনার সম্পূর্ণ বিভাগটি 1313.3 পড়তে হবে। আমি এখানে 100% সঠিক এবং আপনার মান অবধি কোনও উত্তর পাওয়ার বিষয়ে বিশ্বাস করব না।
বিক্রয়বিটজে

আপনি যদি আগ্রহী হন তবে এটির একটি ব্যাখ্যার জন্য আমার উত্তরটি দেখুন।
জোহানেস স্কাউব -

0

আপনার দ্বিতীয় প্রশ্ন অনুসরণ করে, নোট করুন যে এটি কনস্টের জন্য না থাকলে, বি == ডি দিয়ে ইনস্ট্যান্ট করা থাকলে হোস্টটি অসুস্থ হয়ে উঠবে তবে IS_base_of এমনভাবে তৈরি করা হয়েছে যে প্রতিটি শ্রেণি নিজেই একটি বেস, তাই রূপান্তর অপারেটরগুলির মধ্যে একটির অবশ্যই আবশ্যক কনস্ট্যান্ড হতে।

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