টেমপ্লেট <স্বাক্ষরবিহীন এন এন> এর অর্থ কী?


121

কোনও টেম্পলেট ঘোষণা করার সময়, আমি এই জাতীয় কোড রাখার অভ্যস্ত:

template <class T>

তবে এই প্রশ্নে তারা ব্যবহার করেছে:

template <unsigned int N>

আমি পরীক্ষা করেছি যে এটি সংকলন করে। কিন্তু এটার মানে কি? এটি কি একটি নন-টাইপ প্যারামিটার? এবং যদি তা হয়, তবে কোনও প্রকারের প্যারামিটার ছাড়াই আমরা কীভাবে টেমপ্লেট রাখতে পারি?

উত্তর:


147

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

unsigned int x = N;

প্রকৃতপক্ষে, আমরা আলগোরিদিম তৈরি করতে পারি যা সংকলন সময়ে ( উইকিপিডিয়া থেকে ) মূল্যায়ন করে :

template <int N>
struct Factorial 
{
     enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

10
আপনি static constexpr intআপনার পরিবর্তে প্রকারটিও ব্যবহার করতে পারেন enum। সুতরাং Factorial<0>টেমপ্লেটটি থাকতে পারে static constexpr int value = 1এবং template <int N> struct Factorialথাকতে পারেstatic constexpr int value = N * Factorial<N - 1>::value;
bobobobo

@ বোবোবো সি ++ 11 এর আগে এর উত্তর দেওয়া হয়েছিল constexpr
জাস্টিন মাইনার্স

154

হ্যাঁ, এটি একটি নন-টাইপ প্যারামিটার। আপনার বিভিন্ন ধরণের টেম্পলেট প্যারামিটার থাকতে পারে

  • পরামিতি টাইপ করুন।
    • প্রকারভেদ
    • টেমপ্লেটগুলি (কেবল ক্লাস এবং ওরফে টেম্পলেট, কোনও ফাংশন বা ভেরিয়েবল টেম্পলেট)
  • নন-টাইপ পরামিতি
    • পয়েন্টার
    • তথ্যসূত্র
    • অবিচ্ছেদ্য ধ্রুবক প্রকাশ

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

টেমপ্লেট ধরণের পরামিতি:

template<typename T>
struct Container {
    T t;
};

// pass type "long" as argument.
Container<long> test;

টেমপ্লেট পূর্ণসংখ্যা প্যারামিটার:

template<unsigned int S>
struct Vector {
    unsigned char bytes[S];
};

// pass 3 as argument.
Vector<3> test;

টেমপ্লেট পয়েন্টার প্যারামিটার (একটি ফাংশনে একটি পয়েন্টার পাস করে)

template<void (*F)()>
struct FunctionWrapper {
    static void call_it() { F(); }
};

// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;

টেমপ্লেট রেফারেন্স প্যারামিটার (একটি পূর্ণসংখ্যা পাস)

template<int &A>
struct SillyExample {
    static void do_it() { A = 10; }
};

// pass flag as argument
int flag;
SillyExample<flag> test;

টেমপ্লেট টেম্পলেট প্যারামিটার।

template<template<typename T> class AllocatePolicy>
struct Pool {
    void allocate(size_t n) {
        int *p = AllocatePolicy<int>::allocate(n);
    }
};

// pass the template "allocator" as argument. 
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;

কোনও পরামিতি ছাড়াই একটি টেম্পলেট সম্ভব নয়। তবে কোনও সুস্পষ্ট যুক্তি ছাড়াই কোনও টেম্পলেটটি সম্ভব - এতে ডিফল্ট আর্গুমেন্ট রয়েছে:

template<unsigned int SIZE = 3>
struct Vector {
    unsigned char buffer[SIZE];
};

Vector<> test;

সিনট্যাক্টিক্যালি, template<>কোনও পরামিতি ছাড়াই কোনও টেমপ্লেটের পরিবর্তে একটি স্পষ্ট টেম্পলেট বিশেষায়িতকরণ চিহ্নিত করা যায়:

template<>
struct Vector<3> {
    // alternative definition for SIZE == 3
};

জোহনেস, টেমপ্লেটগুলি কি "প্রকার" এর অধীনে দায়ের করা হয়? আমি ভেবেছিলাম সেগুলি কী ধরণের থেকে তৈরি করা যায় তবে তারা নিজেরাই টাইপ করে না?
sbi

@ এসবিআই ব্যাখ্যাটি দেখুন: "এটি স্ট্যান্ডার্ডে দেখার পরে, ক্লাস টেম্পলেটগুলি ধরণের বিভাগে সরিয়ে নিয়ে যেতে হয়েছিল - যদিও টেমপ্লেটগুলি ধরণের নয় But তবে তবুও তাদের এই ধরণের বর্ণনা দেওয়ার উদ্দেশ্যে টাইপ-পরামিতি বলা হয়। "। 14.1 / 2 তে পাদটীকা 126 তাই বলে। এটি কেবলমাত্র অ-টাইপ পরামিতিগুলিকে এমন কিছু তৈরি করার জন্য তৈরি করা শ্রেণি যা মান / রেফারেন্স ঘোষণা করে এবং টাইপ-পরামিতিগুলি কোনও প্রকারের নাম বা টেমপ্লেটের নাম ঘোষণা করে এমন কিছু।
জোহানেস স্কাউব -

@ জোহানেসস্যাচ-লিটব তাই বলে যে স্ট্যাড :: স্ট্রিং দিয়ে টেমপ্লেট টাইপ করার কোনও উপায় নেই? টেমপ্লেটের মতো <স্ট্যান্ড :: স্ট্রিং এস> ক্লাসে কিছু স্ট্যাটিক কাউন্টার রয়েছে যাতে প্রতিটি স্ট্রিংয়ের জন্য অনন্য আইডি তৈরি করা যায়? হ্যাশিং স্ট্রিং টু ইন্টি একমাত্র উপায় দুর্ভাগ্যজনকভাবে সঠিক হবে?
রিলাক্সএক্সএক্স

1
আমি এই উত্তরটি টেমপ্লেট শ্রেণীর সদস্য অবজেক্টস, অর্থাৎ টেমপ্লেট <টাইপনেম সি, টাইপনাম আর, টাইপনাম পি 1, টাইপনাম পি 2> স্ট্রাক্ট মাইস্ট্রাক্ট <আর (সি :: *) (পি 1, পি 2)>
জনি পলিং

সঙ্গে কোডের টুকরা SillyExampleজিসিসি 4.8.4 দ্বারা কম্পাইল করা যাবে না। প্রথম ত্রুটিটি the value of ‘flag’ is not usable in a constant expression। এছাড়াও অন্যান্য ত্রুটি রয়েছে
হেকটো

17

আপনি কোনও 'স্বাক্ষরবিহীন অন্তর্নিহিত' এর উপর ভিত্তি করে আপনার শ্রেণিকে টেম্প্লেটিজ করেছেন।

উদাহরণ:

template <unsigned int N>
class MyArray
{
    public:
    private:
        double    data[N]; // Use N as the size of the array
};

int main()
{
    MyArray<2>     a1;
    MyArray<2>     a2;

    MyArray<4>     b1;

    a1 = a2;  // OK The arrays are the same size.
    a1 = b1;  // FAIL because the size of the array is part of the
              //      template and thus the type, a1 and b1 are different types.
              //      Thus this is a COMPILE time failure.
 }

15

একটি টেম্পলেট শ্রেণি ম্যাক্রোর মতো, কেবলমাত্র পুরোপুরি কম মন্দ।

একটি ম্যাক্রো হিসাবে একটি টেমপ্লেট ভাবেন। আপনি যখন কোনও টেম্পলেট ব্যবহার করে কোনও শ্রেণি (বা ফাংশন) সংজ্ঞায়িত করেন তখন টেমপ্লেটের প্যারামিটারগুলি কোনও শ্রেণি (বা ফাংশন) সংজ্ঞাতে প্রতিস্থাপিত হয়।

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

আপনি পরামিতিগুলির জন্য " class" বা " typename" প্রকারগুলিও ব্যবহার করতে পারেন (তারা আসলে একই রকম)। এই ধরণের যে কোনও একটি প্যারামিটারের সাহায্যে আপনি কোনও মানের পরিবর্তে কোনও প্রকারের নামটি পাস করতে পারেন। ঠিক আগের মতোই, সর্বত্র প্যারামিটারের নামটি টেম্পলেট শ্রেণির সংজ্ঞায় ছিল, আপনি একটি নতুন উদাহরণ তৈরি করার সাথে সাথে আপনি যা যা পাস তা হয়ে যায়। এটি একটি টেম্পলেট শ্রেণীর জন্য সর্বাধিক সাধারণ ব্যবহার; সি ++ টেমপ্লেটগুলির সম্পর্কে যে কোনও কিছু জানেন এমন সবাই এটি কীভাবে জানেন।

এই টেম্পলেট শ্রেণীর উদাহরণ কোডটি বিবেচনা করুন:

#include <cstdio>
template <int I>
class foo
{
  void print()
  {
    printf("%i", I);
  }
};

int main()
{
  foo<26> f;
  f.print();
  return 0;
}

এটি কার্যত এই ম্যাক্রো-ব্যবহার কোড হিসাবে একই:

#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
  void print() \
  { \
    printf("%i", I); \
  } \
};

MAKE_A_FOO(26)

int main()
{
  foo_26 f;
  f.print();
  return 0;
}

অবশ্যই, টেমপ্লেট সংস্করণটি এক বিলিয়নগুণ নিরাপদ এবং আরও নমনীয়।

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