সরকারীভাবে, টাইপনেম কি জন্য?


131

উপলক্ষ্যে আমি কিছু সত্যই অনিবার্য ত্রুটি বার্তাগুলি gccটেমপ্লেটগুলি ব্যবহার করার সময় ছড়িয়ে দিয়ে দেখেছি ... বিশেষত, আমার এমন সমস্যা হয়েছিল যেখানে আপাতদৃষ্টিতে সঠিক ঘোষণাগুলি খুব অদ্ভুত সংকলনের ত্রুটি ঘটিয়েছিল যা ম্যাজিকভাবে প্রথমটির typenameকীওয়ার্ডটির উপসর্গ করে চলে গেছে mag ঘোষণা ... (উদাহরণস্বরূপ, মাত্র গত সপ্তাহে, আমি দুটি পুনরুদ্ধারককে অন্য তাত্পর্যপূর্ণ শ্রেণীর সদস্য হিসাবে ঘোষণা করছিলাম এবং আমাকে এটি করতে হয়েছিল) ...

গল্পটি কী typename?


উত্তর:


207

জোসুটিস বইয়ের উদ্ধৃতিটি নিম্নলিখিত:

কীওয়ার্ডটি typenameশনাক্ত করার জন্য প্রবর্তন করা হয়েছিল যে অনুসরণকারী সনাক্তকারী একটি প্রকার is নিম্নলিখিত উদাহরণ বিবেচনা করুন:

template <class T>
Class MyClass
{
  typename T::SubType * ptr;
  ...
};

এখানে, typenameস্পষ্ট করতে ব্যবহৃত হয় SubTypeযা এক প্রকারের class T। সুতরাং, ptrটাইপ একটি পয়েন্টার T::SubType। ছাড়া typename, SubType একটি স্থির সদস্য হিসাবে বিবেচিত হবে। এইভাবে

T::SubType * ptr

এর সাথে SubTypeটাইপের মানটির একটি গুণ হবে ।Tptr


2
দুর্দান্ত বই। এটি একবার পড়ুন তারপরে আপনার পছন্দ মত একটি রেফারেন্স হিসাবে রাখুন।
ডিফ্ট_কোড

1
বিস্মিত পাঠক বুঝতে পারবেন যে কোনও সদস্যের ঘোষণার জন্য ব্যাকরণ দ্বারা কোনও গুণ প্রকাশের অনুমতি নেই। যেমন সি ++ 20 প্রয়োজন সঙ্গে বিতরণ করেন এই জন্য typename(যদিও তাদের সব না!)।
ডেভিস হেরিং

আমাকে বোঝায়নি। একবার টেমপ্লেটটি ইনস্ট্যান্ট করা হচ্ছে, এটি খুব ভালভাবে সংজ্ঞায়িত করা হয়েছে যে টি ::
সাব টাইপ

36

স্ট্যান লিপম্যানের বিএলগ পোস্টে পরামর্শ দেওয়া হয়েছে: -

স্ট্রাস্ট্রপ একটি নতুন কীওয়ার্ড চালু করার পরিবর্তে প্রকারের পরামিতি নির্দিষ্ট করার জন্য বিদ্যমান শ্রেণীর কীওয়ার্ডটি পুনরায় ব্যবহার করেছিল যা অবশ্যই বিদ্যমান প্রোগ্রামগুলি ভেঙে দিতে পারে। এটি নয় যে কোনও নতুন কীওয়ার্ড বিবেচনা করা হয়নি - কেবল এটির সম্ভাব্য ব্যাঘাতের কারণে এটি প্রয়োজনীয় বিবেচিত হয়নি। এবং আইএসও-সি ++ স্ট্যান্ডার্ড না হওয়া পর্যন্ত টাইপ প্যারামিটার ঘোষণা করার একমাত্র উপায় ছিল।

সুতরাং মূলত স্ট্রস্ট্রপ একটি নতুন কীওয়ার্ড প্রবর্তন না করেই ক্লাস কীওয়ার্ডটিকে পুনরায় ব্যবহার করেছেন যা নিম্নলিখিত কারণে স্ট্যান্ডার্ডে পরে পরিবর্তিত হয়

যেমন দেওয়া হয়েছে

template <class T>
class Demonstration {
public:
void method() {
    T::A *aObj; // oops …
     // …
};

ভাষা ব্যাকরণ T::A *aObj;একটি গাণিতিক অভিব্যক্তি হিসাবে ভুল ব্যাখ্যা করে তাই একটি নতুন কীওয়ার্ড বলা হয়typename

typename T::A* a6;

এটি সংযোজনকারীকে পরবর্তী বিবৃতিটিকে ঘোষণাপত্র হিসাবে আচরণ করার নির্দেশ দেয়।

যেহেতু মূলশব্দটি বেতনভিত্তিতে ছিল, হ্যাক, কেন ক্লাস কীওয়ার্ডটি পুনরায় ব্যবহারের মূল সিদ্ধান্তের কারণে সৃষ্ট বিভ্রান্তি সংশোধন করবেন না

আমাদের দু'জনেই কেন আছে

আপনি এই পোস্টে একবার দেখে নিতে পারেন , এটি অবশ্যই আপনাকে সহায়তা করবে, আমি যতটা পেরেছি তা থেকে এটিকে সরিয়েছি


হ্যাঁ, তবে তারপরে নতুন কীওয়ার্ডটি কেন typenameপ্রয়োজনীয় ছিল, যদি আপনি classএকই উদ্দেশ্যে বিদ্যমান কীওয়ার্ডটি ব্যবহার করতে পারেন ?
জেস্পার

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

13

কোডটি বিবেচনা করুন

template<class T> somefunction( T * arg )
{
    T::sometype x; // broken
    .
    .

দুর্ভাগ্যক্রমে, সংকলকটির মনস্তাত্ত্বিক হওয়ার প্রয়োজন নেই, এবং টি :: কিছুটা টাইপের নাম বা টি এর স্থির সদস্যের উল্লেখ করে শেষ হবে কিনা তা জানে না So সুতরাং, কেউ typenameএটি বলার জন্য ব্যবহার করে:

template<class T> somefunction( T * arg )
{
    typename T::sometype x; // works!
    .
    .

6

কিছু পরিস্থিতিতে যেখানে আপনি তথাকথিত নির্ভরশীল কোনও সদস্যকে উল্লেখ করেন ধরণের বোঝায় (যার অর্থ "টেমপ্লেট প্যারামিটারের উপর নির্ভরশীল"), সংকলক সর্বদা নির্বিঘ্নে ফলাফল নির্মাণকারীটির অর্থকৃত অর্থটি কাটাতে পারে না, কারণ এটি কী ধরনের নাম তা জানে না that (যেমন এটি কোনও প্রকারের নাম, কোনও ডেটা সদস্যের নাম বা অন্য কোনও কিছুর নাম)। এরকম ক্ষেত্রে আপনাকে স্পষ্ট করে সংকলককে জানিয়ে দিতে হবে যে নামটি নির্ভরশীল ধরণের সদস্য হিসাবে সংজ্ঞায়িত কোনও টাইপনের সাথে সম্পর্কিত।

উদাহরণ স্বরূপ

template <class T> struct S {
  typename T::type i;
};

এই উদাহরণে typenameকোডটি সংকলনের জন্য প্রয়োজনীয় কীওয়ার্ড ।

আপনি যখন নির্ভরশীল ধরণের কোনও টেম্পলেট সদস্যকে উল্লেখ করতে চান, তেমনি কোনও নামটি যা কোনও টেমপ্লেটকে মনোনীত করে The আপনাকে কীওয়ার্ডটি ব্যবহার করে সংকলকটিকে সহায়তা করতে templateহবে, যদিও এটি আলাদাভাবে স্থাপন করা হয়েছে

template <class T> struct S {
  T::template ptr<int> p;
};

কিছু ক্ষেত্রে এটি উভয় ব্যবহারের প্রয়োজন হতে পারে

template <class T> struct S {
  typename T::template ptr<int>::type i;
};

(যদি আমি সিনট্যাক্সটি সঠিকভাবে পেলাম)।

অবশ্যই, কীওয়ার্ডের আরেকটি ভূমিকা typenameহ'ল টেমপ্লেট প্যারামিটারের ঘোষণাগুলিতে ব্যবহার করা।


আরও দেখুন সি ++ typename শব্দ এ ডেসক্রিপশন অফ দ্য জন্য আরো (পটভূমি) তথ্য।
আতফর

5

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

template<typename T>
struct test {
    typedef T* ptr;
};

template<>         // complete specialization 
struct test<int> { // for the case T is int
    T* ptr;
};

কেউ জিজ্ঞাসা করতে পারেন কেন এটি দরকারী এবং সত্যই: এটি সত্যিই অকেজো দেখাচ্ছে। কিন্তু মনের মধ্যে নিতে যে উদাহরণস্বরূপ টাইপ অপরের জন্য চেয়ে সম্পূর্ণ ভিন্ন দেখায় সে। স্বীকার করা যায় যে এটি এক ধরণের থেকে আলাদা কিছুতে পরিবর্তন করে না তবুও এটি ঘটতে পারে।std::vector<bool>referenceTreference

এখন এই testটেমপ্লেটটি ব্যবহার করে আপনি নিজের টেম্পলেটগুলি লিখলে কী হয় । এটার মতো কিছু

template<typename T>
void print(T& x) {
    test<T>::ptr p = &x;
    std::cout << *p << std::endl;
}

এটা তোমার জন্য ঠিক করা কারণ আপনার মনে হয় আশা যে test<T>::ptrএকটি প্রকার। তবে সংকলকটি জানে না এবং কৃতকর্মের সাথে তার এমনকি বিপরীতটি প্রত্যাশা করার মানদণ্ড দ্বারা পরামর্শ দেওয়া হয়, test<T>::ptrএটি কোনও প্রকার নয়। সংকলকটি আপনি যা আশা করেন তা জানানোর জন্য আপনাকে typenameআগে যুক্ত করতে হবে। সঠিক টেমপ্লেটটি এর মতো দেখাচ্ছে

template<typename T>
void print(T& x) {
    typename test<T>::ptr p = &x;
    std::cout << *p << std::endl;
}

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


5

দুটি ব্যবহার:

  1. templateআর্গুমেন্ট কীওয়ার্ড হিসাবে (পরিবর্তে class)
  2. একটি typenameকীওয়ার্ড সংকলককে বলে যে একটি সনাক্তকারী একটি প্রকার (স্থির সদস্যের পরিবর্তে পরিবর্তিত)
template <typename T> class X  // [1]
{
    typename T::Y _member;  // [2] 
}

4

আমি মনে করি যে সমস্ত জবাবই উল্লেখ করেছে যে মূল typenameশব্দটি দুটি ভিন্ন ক্ষেত্রে ব্যবহৃত হয়:

ক) টেমপ্লেট ধরণের পরামিতি ঘোষণার সময়। যেমন

template<class T> class MyClass{};        // these two cases are
template<typename T> class MyNewClass{};  // exactly the same.

যা তাদের মধ্যে কোনও পার্থক্য নেই এবং তারা একেবারে একই।

খ) কোনও টেমপ্লেটের জন্য নেস্টেড নির্ভর নির্ভর টাইপ নাম ব্যবহার করার আগে ।

template<class T>
void foo(const T & param)
{
   typename T::NestedType * value; // we should use typename here
}

যা typenameপার্সিং / সংকলন ত্রুটির দিকে পরিচালিত করে না ।

স্কট মায়ার্স বই ইফেক্টিভ সি ++ তে উল্লিখিত হিসাবে আমি দ্বিতীয় ক্ষেত্রে যা যুক্ত করতে চাই তা হ'ল নেস্টেড নির্ভর নির্ভর টাইপের নামেরtypename আগে ব্যবহার করার ব্যতিক্রম রয়েছে । ব্যতিক্রমটি হ'ল আপনি যদি নেস্টড নির্ভরশীল টাইপ নামটি হয় বেস ক্লাস হিসাবে বা সদস্য সূচনা তালিকায় ব্যবহার করেন তবে আপনার সেখানে ব্যবহার করা উচিত নয় :typename

template<class T>
class D : public B<T>::NestedType               // No need for typename here
{
public:
   D(std::string str) : B<T>::NestedType(str)   // No need for typename here
   {
      typename B<T>::AnotherNestedType * x;     // typename is needed here
   }
}

নোট: ব্যবহার typenameদ্বিতীয় ক্ষেত্রে জন্য (অর্থাত নেস্টেড নির্ভরশীল টাইপ নাম আগে) সি যেহেতু ++, 20 প্রয়োজন হয় না।


2
#include <iostream>

class A {
public:
    typedef int my_t;
};

template <class T>
class B {
public:
    // T::my_t *ptr; // It will produce compilation error
    typename T::my_t *ptr; // It will output 5
};

int main() {
    B<A> b;
    int my_int = 5;
    b.ptr = &my_int;
    std::cout << *b.ptr;
    std::cin.ignore();
    return 0;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.