টেমপ্লেট টেম্পলেট প্যারামিটারগুলির কিছু ব্যবহার কী?


238

নীতি-ভিত্তিক শ্রেণীর নকশা করতে আমি টেমপ্লেট টেম্পলেট প্যারামিটারগুলি ব্যবহার করে সি ++ এর কয়েকটি উদাহরণ দেখেছি (এটি টেমপ্লেটগুলি যা প্যারামিটার হিসাবে টেমপ্লেট গ্রহণ করে)। এই কৌশলটি অন্য কি ব্যবহার আছে?


4
আমি অন্য দিক থেকে এসেছি (এফপি, হাস্কেল ইত্যাদি) এবং এটিতে
এরিক কাপলুন

উত্তর:


197

আমি মনে করি যে এমন প্যারামিটারটি পাস করার জন্য আপনাকে টেমপ্লেট টেমপ্লেট সিনট্যাক্স ব্যবহার করতে হবে যার প্রকারের মতো অন্য টেম্পলেটের উপর নির্ভরশীল একটি টেম্পলেট:

template <template<class> class H, class S>
void f(const H<S> &value) {
}

এখানে, Hএকটি টেমপ্লেট, তবে আমি এই ফাংশনটি সমস্ত বিশেষত্বের সাথে ডিল করতে চেয়েছিলাম H

দ্রষ্টব্য : আমি বহু বছর ধরে সি ++ প্রোগ্রামিং করে চলেছি এবং কেবল এটির জন্য একবারের দরকার পড়ে। আমি দেখতে পেলাম যে এটি খুব কমই প্রয়োজনীয় বৈশিষ্ট্য (অবশ্যই যখন আপনার প্রয়োজন হবে তখন কার্যকর!)।

আমি ভাল উদাহরণগুলি চিন্তা করার চেষ্টা করেছি, এবং সত্যি বলতে, বেশিরভাগ সময় এটি প্রয়োজন হয় না, তবে আসুন একটি উদাহরণ তৈরি করি। এর সাজা করা যাক যে std::vector নেই একটি আছে typedef value_type

সুতরাং আপনি কীভাবে কোনও ফাংশন লিখবেন যা ভেক্টর উপাদানগুলির জন্য সঠিক ধরণের ভেরিয়েবল তৈরি করতে পারে? এটি কাজ করবে।

template <template<class, class> class V, class T, class A>
void f(V<T, A> &v) {
    // This can be "typename V<T, A>::value_type",
    // but we are pretending we don't have it

    T temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;
}

দ্রষ্টব্য : std::vectorদুটি টেম্পলেট প্যারামিটার, টাইপ, এবং বরাদ্দকারী রয়েছে, তাই আমাদের উভয়টিকেই গ্রহণ করতে হয়েছিল। ভাগ্যক্রমে, টাইপ ছাড়ের কারণে, আমাদের সঠিক টাইপটি স্পষ্টভাবে লিখতে হবে না।

যা আপনি এটির মতো ব্যবহার করতে পারেন:

f<std::vector, int>(v); // v is of type std::vector<int> using any allocator

বা আরও ভাল, আমরা কেবল ব্যবহার করতে পারি:

f(v); // everything is deduced, f can deal with a vector of any type!

আপডেট : এমনকি এই সংকীর্ণ উদাহরণটি উদাহরণস্বরূপ, সি ++ 11 প্রবর্তনের কারণে আর আশ্চর্যজনক উদাহরণ নয় auto। এখন একই ফাংশন হিসাবে লেখা যেতে পারে:

template <class Cont>
void f(Cont &v) {

    auto temp = v.back();
    v.pop_back();
    // Do some work on temp

    std::cout << temp << std::endl;
}

যা আমি এই জাতীয় কোড লিখতে পছন্দ করব।


1
যদি f কোনও লাইব্রেরির ব্যবহারকারী দ্বারা নির্ধারিত একটি ফাংশন হয় তবে এটি কুশ্রী যে ব্যবহারকারীর std :: বরাদ্দকারী <T> একটি আর্গুমেন্ট হিসাবে পাস করতে হবে। আমি আশা করতাম যে এইচটিডি :: বরাদ্দকারী যুক্তি ব্যতীত সংস্করণটি স্ট্যান্ড :: ভেক্টরের ডিফল্ট প্যারামিটার ব্যবহার করে কাজ করেছে। এই আর্ট সি ++ 0x এর কোনও আপডেট আছে?
amit

ভাল, আপনি বরাদ্দ সরবরাহ করতে হবে না। গুরুত্বপূর্ণটি হ'ল টেমপ্লেট টেম্পলেট প্যারামিটারটি সঠিক সংখ্যক আর্গুমেন্টের উপরে সংজ্ঞায়িত করা হয়েছিল। তবে ফাংশনটি তাদের "প্রকার" বা অর্থ কী তা বিবেচনা করবে না, নিম্নলিখিতটি C ++ 98 এ ভালভাবে কাজ করে:template<template<class, class> class C, class T, class U> void f(C<T, U> &v)
pfalcon

আমি অবাক হই কেন তাত্ক্ষণিকতা f<vector,int>এবং না f<vector<int>>
বোবোবোবো

2
@ বোবোবো এই দুটি অর্থ ভিন্ন জিনিস। f<vector,int>অর্থ f<ATemplate,AType>, f<vector<int>>অর্থf<AType>
ব্যবহারকারী 362515

@ ফায়েদরাস: (অনেক পরে ...) ভাল পয়েন্টগুলি, বরাদ্দকারীকে জেনেরিক এবং উদাহরণটিকে আরও স্পষ্ট করে তুলতে উদাহরণটির উন্নতি করেছে :-)
ইভান তেরান

163

আসলে, টেমপ্লেট টেমপ্লেট পরামিতিগুলির জন্য ইউজকেস বরং স্পষ্ট। একবার আপনি যখন জানতে পারবেন যে সি ++ স্ট্ডলিবের স্ট্যান্ড আউটপুট অপারেটরগুলিকে স্ট্যান্ডার্ড ধারক প্রকারের জন্য সংজ্ঞায়িত না করার ফাঁক গর্ত রয়েছে, আপনি এরকম কিছু লেখার জন্য এগিয়ে যাবেন:

template<typename T>
static inline std::ostream& operator<<(std::ostream& out, std::list<T> const& v)
{
    out << '[';
    if (!v.empty()) {
        for (typename std::list<T>::const_iterator i = v.begin(); ;) {
            out << *i;
            if (++i == v.end())
                break;
            out << ", ";
        }
    }
    out << ']';
    return out;
}

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

template<template <typename, typename> class Container, class V, class A>
std::ostream& operator<<(std::ostream& out, Container<V, A> const& v)
...

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

বিটিডব্লিউ, সি + ১১ দিয়ে যা ভেরিয়াদিক টেম্পলেটগুলিকে অনুমতি দেয় (এবং এর ফলে ভের্যাদিক টেম্পলেট টেম্পলেট আরোগুলিকে অনুমতি দেওয়া উচিত), একক অপারেটর থাকা সম্ভব হবে << সেগুলি সমস্তই নিয়ন্ত্রণ করতে পারে। উদাহরণ স্বরূপ:

#include <iostream>
#include <vector>
#include <deque>
#include <list>

template<typename T, template<class,class...> class C, class... Args>
std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs)
{
    os << __PRETTY_FUNCTION__ << '\n';
    for (auto const& obj : objs)
        os << obj << ' ';
    return os;
}

int main()
{
    std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
    std::cout << vf << '\n';

    std::list<char> lc { 'a', 'b', 'c', 'd' };
    std::cout << lc << '\n';

    std::deque<int> di { 1, 2, 3, 4 };
    std::cout << di << '\n';

    return 0;
}

আউটপুট

std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = float, C = vector, Args = <std::__1::allocator<float>>]
1.1 2.2 3.3 4.4 
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = char, C = list, Args = <std::__1::allocator<char>>]
a b c d 
std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = int, C = deque, Args = <std::__1::allocator<int>>]
1 2 3 4 

9
এটি টেমপ্লেট টেম্পলেট পরামিতিগুলির একটি মিষ্টি উদাহরণ, কারণ এটি এমন একটি কেস দেখায় যা প্রত্যেকে মোকাবেলা করতে হয়েছিল।
রেভেন ওয়াটার

3
এটি আমার জন্য সি ++ টেমপ্লেটগুলির মধ্যে সর্বাধিক জাগ্রত উত্তর। @WhozCraig আপনি কীভাবে টেমপ্লেট সম্প্রসারণের বিশদটি পেয়েছেন?
অরুণ

3
@ অরুন জিসিসি একটি ম্যাক্রো নামে পরিচিত __PRETTY_FUNCTION__, যা অন্যান্য বিষয়গুলির মধ্যেও, সরল পাঠ্যে টেমপ্লেট প্যারামিটারের বিবরণ জানায়। ঝাঁকুনি পাশাপাশি এটি করে। একটি খুব সুবিধাজনক বৈশিষ্ট্য কখনও কখনও (আপনি দেখতে পারেন)।
WhozCraig

20
এখানে টেমপ্লেট টেমপ্লেট প্যারামিটারটি আসলে কোনও মান যুক্ত করছে না। আপনি কেবলমাত্র কোনও শ্রেণিবদ্ধ টেমপ্লেটের যে কোনও উদাহরণ হিসাবে নিয়মিত টেম্পলেট প্যারামিটার ব্যবহার করতে পারেন।
ডেভিড স্টোন

9
আমাকে ডেভিড স্টোনর সাথে একমত হতে হবে। এখানে টেমপ্লেট টেম্পলেট প্যারামিটারের কোনও বিন্দু নেই। এটি একটি সরল টেম্পলেট (টেমপ্লেট <টাইপনেম ধারক>) তৈরি করা অনেক সহজ এবং সমান কার্যকর। আমি জানি যে এই পোস্টটি বেশ পুরানো, সুতরাং আমি এই টেমপ্লেট টেমপ্লেটগুলি সম্পর্কে তথ্য খুঁজছেন যারা এই উত্তর জুড়ে হোঁচট খাচ্ছেন তাদের জন্য আমি কেবল আমার 2 সেন্ট যুক্ত করছি।
জিম ভার্গো 21

67

এন্ড্রেই আলেকজান্দ্রেস্কু কর্তৃক 'মডার্ন সি ++ ডিজাইন - জেনেরিক প্রোগ্রামিং এবং ডিজাইনের প্যাটার্ন প্রয়োগ করা' থেকে নেওয়া একটি সাধারণ উদাহরণ এখানে :

নীতি প্যাটার্নটি প্রয়োগ করতে তিনি টেমপ্লেট টেম্পলেট পরামিতি সহ একটি ক্লাস ব্যবহার করেন:

// Library code
template <template <class> class CreationPolicy>
class WidgetManager : public CreationPolicy<Widget>
{
   ...
};

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

এর প্রভাবটি হ'ল ক্লায়েন্ট কোডটি আরও মার্জিত উপায়ে 'উইজেটম্যানেজার' ব্যবহার করতে পারে:

typedef WidgetManager<MyCreationPolicy> MyWidgetMgr;

আরও জটিল, এবং ত্রুটিযুক্ত প্রবণতার পরিবর্তে কোনও সংজ্ঞা টেম্পলেট টেমপ্লেটের আর্গুমেন্টের অভাবের প্রয়োজন হত:

typedef WidgetManager< MyCreationPolicy<Widget> > MyWidgetMgr;

1
প্রশ্নটি নীতি প্যাটার্ন ব্যতীত অন্য উদাহরণগুলির জন্য বিশেষভাবে অনুরোধ করেছে।
ব্যবহারকারী 2913094

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

18

আমার সিইউডিএ কনভলিউশনাল নিউরাল নেটওয়ার্ক লাইব্রেরি থেকে অন্য একটি ব্যবহারিক উদাহরণ এখানে । আমার নিম্নলিখিত ক্লাস টেম্পলেট রয়েছে:

template <class T> class Tensor

যা আসলে এন-ডাইমেনশনাল ম্যাট্রিকেস ম্যানিপুলেশন প্রয়োগ করে। এখানে একটি শিশু শ্রেণির টেম্পলেটও রয়েছে:

template <class T> class TensorGPU : public Tensor<T>

যা একই কার্যকারিতা প্রয়োগ করে তবে জিপিইউতে। উভয় টেমপ্লেটগুলি সমস্ত মূল ধরণের সাথে কাজ করতে পারে, যেমন ভাসা, ডাবল, ইনট ইত্যাদি And

template <template <class> class TT, class T> class CLayerT: public Layer<TT<T> >
{
    TT<T> weights;
    TT<T> inputs;
    TT<int> connection_matrix;
}

এখানে টেমপ্লেট টেমপ্লেট সিনট্যাক্স থাকার কারণ হ'ল আমি শ্রেণীর প্রয়োগের ঘোষণা করতে পারি

class CLayerCuda: public CLayerT<TensorGPU, float>

যার টাইপ ফ্লোট এবং জিপিইউতে ওজন এবং ইনপুট উভয়ই থাকবে, তবে সংযোগ_ম্যাট্রিক্স সর্বদা সিপিইউতে (টিটি = টেনসর উল্লেখ করে) বা জিপিইউতে (টিটি = টেনসরপিপি নির্দিষ্ট করে) থাকবে।


আপনি কি টি এর ছাড়ের মতো কিছু দিয়ে জোর করতে পারেন: "টেমপ্লেট <ক্লাস টি, টেম্পলেট <টি> টিটি> সিএয়ারটি" এবং "ক্লাস ক্লায়ারকুডা: পাবলিক সিএইয়ারটি <টেনসরজিপি <ফ্লোট>>"? যদি আপনার কোনও টিটি প্রয়োজন না <<< অন্যটি>
নিকো বেরোগুরি

কখনও মাইন্ড: টেমপ্লেট <টেমপ্লেট <ক্লাস টি> শ্রেণি ইউ> শ্রেণি বি 1 {}; একটি দ্রুত গুগল অনুসন্ধান থেকে আইবিএম.com/সপোর্ট / জ্ঞানসেন্টার/en/SSLTBW_2.3.0/… থেকে
নিকো বেরোগুরি

12

বলুন আপনি শিশু টেম্পলেটগুলির একটি সেট জন্য "ইন্টারফেস" সরবরাহ করতে সিআরটিপি ব্যবহার করছেন; এবং পিতা-মাতা এবং শিশু উভয়ই অন্যান্য টেম্পলেট যুক্তিতে (গুলি) প্যারাম্যাট্রিক ric

template <typename DERIVED, typename VALUE> class interface {
    void do_something(VALUE v) {
        static_cast<DERIVED*>(this)->do_something(v);
    }
};

template <typename VALUE> class derived : public interface<derived, VALUE> {
    void do_something(VALUE v) { ... }
};

typedef interface<derived<int>, int> derived_t;

'Int' এর সদৃশটি নোট করুন, যা আসলে উভয় টেমপ্লেটগুলিতে নির্দিষ্ট একই পরামিতি। এই সদৃশটি এড়াতে আপনি ডেরাইভেডের জন্য একটি টেম্পলেট টেম্পলেট ব্যবহার করতে পারেন:

template <template <typename> class DERIVED, typename VALUE> class interface {
    void do_something(VALUE v) {
        static_cast<DERIVED<VALUE>*>(this)->do_something(v);
    }
};

template <typename VALUE> class derived : public interface<derived, VALUE> {
    void do_something(VALUE v) { ... }
};

typedef interface<derived, int> derived_t;

নোট করুন যে আপনি সরাসরি উত্পন্ন টেম্পলেটটিতে অন্যান্য টেম্পলেট প্যারামিটারগুলি সরবরাহ করছেন ; "ইন্টারফেস" এখনও তাদের গ্রহণ করে।

এটি আপনাকে "ইন্টারফেস" এ টাইপডেফগুলি তৈরি করতে দেয় যা ধরণের পরামিতিগুলির উপর নির্ভর করে, যা উত্পন্ন টেম্পলেট থেকে অ্যাক্সেসযোগ্য হবে।

উপরের টাইপিডেফ কাজ করে না কারণ আপনি কোনও অনির্ধারিত টেম্পলেটটিতে টাইপ করতে পারবেন না। এটি কাজ করে তবে (এবং সি ++ 11 এর টেম্পলেট টাইপডেফের জন্য স্থানীয় সমর্থন রয়েছে):

template <typename VALUE>
struct derived_interface_type {
    typedef typename interface<derived, VALUE> type;
};

typedef typename derived_interface_type<int>::type derived_t;

দুর্ভাগ্যক্রমে, উত্পন্ন টেমপ্লেটের প্রতিটি ইনস্ট্যান্টিশনের জন্য আপনার একটি derised_interface_type দরকার, যদি না আমি এখনও শিখি না এমন অন্য কৌশল unless


কিছু কোডের জন্য আমার এই সঠিক সমাধানটি প্রয়োজন (ধন্যবাদ!) যদিও এটি কাজ করে, আমি বুঝতে পারি না যে টেম্পলেট শ্রেণিটি কীভাবে derivedএটির টেমপ্লেট যুক্তি ছাড়াই ব্যবহার করা যেতে পারে, অর্থাৎ লাইনটিtypedef typename interface<derived, VALUE> type;
কার্লটন

@ কার্লটন এটি মূলত কাজ করে কারণ সংশ্লিষ্ট টেম্পলেট পরামিতি পূরণ করা হয় এটি হিসাবে সংজ্ঞায়িত template <typename>। এক অর্থে আপনি টেমপ্লেট প্যারামিটারগুলিকে একটি 'মেটাটাইপ' বলে মনে করতে পারেন; টেমপ্লেট প্যারামিটারের সাধারণ মেটাটাইপটি typenameযার অর্থ এটি একটি নিয়মিত ধরণের দ্বারা পূরণ করা প্রয়োজন; templatemetatype মানে দরকার একটি টেমপ্লেট একটি রেফারেন্স দিয়ে পূর্ণ করা হবে। derivedএমন একটি টেমপ্লেট সংজ্ঞায়িত করে যা একটি typenameমেটাটাইপড প্যারামিটার গ্রহণ করে , সুতরাং এটি বিলটি ফিট করে এবং এখানে উল্লেখ করা যেতে পারে। ধারণা তৈরী কর?
মার্ক ম্যাকেন্না

সি ++ 11 এখনও এখনও typedef। এছাড়াও, আপনি ডাইরাইভেড প্রকারের intমতো একটি স্ট্যান্ডার্ড কনস্ট্রাক্ট ব্যবহার করে আপনার প্রথম উদাহরণে সদৃশটিকে এড়াতে পারবেন value_type
রুবেনভবি

এই উত্তরটি আসলে সি ++ 11 কে লক্ষ্য করে না; আমি typedefব্লক ২ থেকে সমস্যাটি পেতে পারি বলে কেবল সি ++ ১১ উল্লেখ করেছি তবে পয়েন্ট 2 বৈধ বলে আমি মনে করি ... হ্যাঁ, সম্ভবত এটি একই কাজ করার সহজ উপায় হবে।
মার্ক ম্যাকেন্না

7

এটিই আমি ছুটে এসেছি:

template<class A>
class B
{
  A& a;
};

template<class B>
class A
{
  B b;
};

class AInstance : A<B<A<B<A<B<A<B<... (oh oh)>>>>>>>>
{

};

এতে সমাধান করা যেতে পারে:

template<class A>
class B
{
  A& a;
};

template< template<class> class B>
class A
{
  B<A> b;
};

class AInstance : A<B> //happy
{

};

বা (কার্য কোড):

template<class A>
class B
{
public:
    A* a;
    int GetInt() { return a->dummy; }
};

template< template<class> class B>
class A
{
public:
    A() : dummy(3) { b.a = this; }
    B<A> b;
    int dummy;
};

class AInstance : public A<B> //happy
{
public:
    void Print() { std::cout << b.GetInt(); }
};

int main()
{
    std::cout << "hello";
    AInstance test;
    test.Print();
}

4

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

#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <map>

namespace containerdisplay
{
  template<typename T, template<class,class...> class C, class... Args>
  std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs)
  {
    std::cout << __PRETTY_FUNCTION__ << '\n';
    for (auto const& obj : objs)
      os << obj << ' ';
    return os;
  }  
}

template< typename K, typename V>
std::ostream& operator << ( std::ostream& os, 
                const std::map< K, V > & objs )
{  

  std::cout << __PRETTY_FUNCTION__ << '\n';
  for( auto& obj : objs )
  {    
    os << obj.first << ": " << obj.second << std::endl;
  }

  return os;
}


int main()
{

  {
    using namespace containerdisplay;
    std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 };
    std::cout << vf << '\n';

    std::list<char> lc { 'a', 'b', 'c', 'd' };
    std::cout << lc << '\n';

    std::deque<int> di { 1, 2, 3, 4 };
    std::cout << di << '\n';
  }

  std::map< std::string, std::string > m1 
  {
      { "foo", "bar" },
      { "baz", "boo" }
  };

  std::cout << m1 << std::endl;

    return 0;
}

2

আমি সবেমাত্র ব্যবহার করেছি এমন কিছু থেকে এখানে একটি সাধারণীকৃত। এটি একটি খুব সাধারণ উদাহরণ হিসাবে আমি এটি পোস্ট করছি এবং এটি ডিফল্ট যুক্তিগুলির সাথে ব্যবহারিক ব্যবহারের ক্ষেত্রেও প্রদর্শন করে:

#include <vector>

template <class T> class Alloc final { /*...*/ };

template <template <class T> class allocator=Alloc> class MyClass final {
  public:
    std::vector<short,allocator<short>> field0;
    std::vector<float,allocator<float>> field1;
};

2

এটি আপনার কোডের পঠনযোগ্যতা উন্নত করে, অতিরিক্ত ধরণের সুরক্ষা সরবরাহ করে এবং কিছু সংকলক প্রচেষ্টা সংরক্ষণ করে।

বলুন আপনি কোনও ধারকটির প্রতিটি উপাদান মুদ্রণ করতে চান, আপনি টেমপ্লেট টেম্পলেট প্যারামিটার ছাড়াই নিম্নলিখিত কোডটি ব্যবহার করতে পারেন

template <typename T> void print_container(const T& c)
{
    for (const auto& v : c)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}

অথবা টেমপ্লেট টেম্পলেট প্যারামিটার সহ

template< template<typename, typename> class ContainerType, typename ValueType, typename AllocType>
void print_container(const ContainerType<ValueType, AllocType>& c)
{
    for (const auto& v : c)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}

আপনি একটি পূর্ণসংখ্যা বলে মধ্যে পাস ধরে print_container(3)। পূর্ববর্তী ক্ষেত্রে, টেমপ্লেট সংকলক দ্বারা ইনস্ট্যান্ট করা হবে যা cলুপের জন্য লুপের ব্যবহার সম্পর্কে অভিযোগ করবে , পরবর্তী কোনও টেম্পলেটটি খুঁজে পাওয়া যায় না বলে টেমপ্লেটটি একেবারে ইনস্ট্যান্ট করবে না।

সাধারণভাবে বলতে গেলে, যদি আপনার টেম্পলেট শ্রেণি / ফাংশনটি টেম্পলেট শ্রেণিটিকে টেমপ্লেট প্যারামিটার হিসাবে পরিচালনা করতে ডিজাইন করা থাকে তবে এটি পরিষ্কার করা আরও ভাল।


1

আমি এটি সংস্করণযুক্ত ধরণের জন্য ব্যবহার করি।

আপনার যদি কোনও টেমপ্লেটের মাধ্যমে সংস্করণযুক্ত যেমন থাকে তবে MyType<version>আপনি এমন একটি ফাংশন লিখতে পারেন যাতে আপনি সংস্করণ নম্বরটি ক্যাপচার করতে পারেন:

template<template<uint8_t> T, uint8_t Version>
Foo(const T<Version>& obj)
{
    assert(Version > 2 && "Versions older than 2 are no longer handled");
    ...
    switch (Version)
    {
    ...
    }
}

সুতরাং আপনি প্রতিটি ধরণের ওভারলোডের পরিবর্তে প্রকারটি যে ধরণের পাস হচ্ছে তা নির্ভর করে বিভিন্ন জিনিস করতে পারেন। আপনার জেনেরিক উপায়ে রূপান্তর ফাংশন থাকতে পারে MyType<Version>এবং ফিরে আসতে MyType<Version+1>পারে এবং এমনকি ToNewest()কোনও পুরানো সংস্করণ থেকে কোনও ধরণের সর্বশেষতম সংস্করণ ফেরত দেয় এমন ফাংশনটি পুনরুদ্ধার করতে পারে (লগগুলির জন্য খুব দরকারী যে কিছুক্ষণ আগে সঞ্চিত থাকতে পারে) তবে আজকের নবীনতম সরঞ্জাম দিয়ে প্রক্রিয়া করা প্রয়োজন)।

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