ফাংশন টেম্পলেটগুলির জন্য ডিফল্ট টেম্পলেট আর্গুমেন্ট


187

ডিফল্ট টেম্পলেট আর্গুমেন্টগুলি কেবল শ্রেণীর টেম্পলেটগুলিতে কেন অনুমোদিত? সদস্য ফাংশন টেম্পলেটে আমরা ডিফল্ট ধরণের সংজ্ঞা দিতে পারি না কেন? উদাহরণ স্বরূপ:

struct mycclass {
  template<class T=int>
  void mymember(T* vec) {
    // ...
  }
};

পরিবর্তে, সি ++ জোর করে যে ডিফল্ট টেম্পলেট আর্গুমেন্টগুলি কেবল শ্রেণির টেম্পলেটে অনুমোদিত।


8
+1 এটি সত্যিই একটি জটিল প্রশ্ন।
আরাক

1
প্রথম তিনটি পোস্ট করা উত্তরের জন্য, এই উদাহরণটি বিবেচনা করুন: struct S { template <class R = int> R get_me_R() { return R(); } };টেমপ্লেট প্যারামিটারটি প্রসঙ্গ থেকে বাদ দেওয়া যায় না।
আরাক

3
ভাল প্রশ্ন. 3 জন ইতিমধ্যে এটির "অর্থবোধ করে না" বলে জবাব দিয়েছেন এবং তারা সাধারণভাবে সমস্ত ভুল're ফাংশন কল প্যারামিটারগুলি থেকে ফাংশন টেম্পলেট পরামিতিগুলি সর্বদা ছাড়যোগ্য হয় না । উদাহরণস্বরূপ, যদি তাদের অনুমতি দেওয়া হয় আমি লিখতে পারি template <int N = 1> int &increment(int &i) { i += N; return i; }এবং তারপরে increment(i);বা increment<2>(i);। যেমনটি আছে, আমাকে লিখতে হবে increment<1>(i);
স্টিভ জেসোপ

আসলে, আমার এবং আরকের উদাহরণ উভয়ই ওভারলোডিং দিয়ে মোকাবেলা করা যেতে পারে। litb এর পারে না, আমি মনে করি, কারণ টেমপ্লেট প্যারামিটারগুলি ছাড়ানো হতে পারে বা নির্দিষ্ট করা যেতে পারে।
স্টিভ জেসোপ

3
@Steve: অনুপস্থিত সেমিকোলন আসলে পরিপূর্ণ করার জন্য বি Stavtrup এর অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর জার্নাল, এপ্রিল 1, 1992 সালে প্রকাশিত "সি ++ হোয়াইটস্পেস এর ওভারলোডিং" (একটি নতুন EOL অপারেটর জমিদার হয় www2.research.att.com/~bs/ কাগজস.এইচটিএমএল )

উত্তর:


148

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

template<typename Iterator, 
         typename Comp = std::less<
            typename std::iterator_traits<Iterator>::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
  ...
}

সি ++ 0x তাদের সি ++ এর সাথে পরিচয় করিয়ে দেয়। বার্জন স্ট্রস্ট্রপের এই ত্রুটি প্রতিবেদনটি দেখুন: ফাংশন টেম্পলেটগুলির জন্য ডিফল্ট টেম্পলেট আর্গুমেন্ট এবং তিনি যা বলেছেন

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

এই বিধিনিষেধটি অযৌক্তিকভাবে ফ্রিস্ট্যান্ডিং ফাংশনকে সদস্য ফাংশন থেকে আলাদা করে প্রোগ্রামিং স্টাইলকে মারাত্মকভাবে সঙ্কুচিত করে, ফলে এসটিএল-স্টাইল কোডটি লেখা শক্ত করে তোলে।


@ আরমান, ত্রুটিযুক্ত প্রতিবেদনের লিঙ্কটিতে সি ++ 0 এক্স এবং আলোচনার জন্য ওয়ার্কিং ড্রাফ্টে করা পরিবর্তনগুলি রয়েছে। ছাড় বা স্পষ্টভাবে বর্ণিত আর্গুমেন্টগুলি ডিফল্ট আর্গুমেন্টগুলি থেকে প্রাপ্ত হয়। GCC4.4 সি ++ 0x মোডে ফাংশন টেম্পলেটগুলির জন্য ডিফল্ট যুক্তিগুলি সমর্থন করে supports
জোহানেস স্কাউব - লিটব

4
প্রশ্ন বা উত্তর দিয়ে কিছুই করার নেই, তবে হার্ব সটার গত শনিবার সভার পরে আপকমিং স্ট্যান্ডার্ড সি ++ 11 বলেছিল called আমি এটি আজই পড়েছি এবং ভাগ করে নেওয়ার মতো অনুভব করছি :) herbsutter.wordpress.com/2010/03/13/…
ডেভিড রদ্রিগেজ - শুক্রবার

এবং বাধ্যতামূলক ফলোআপ প্রশ্ন ... অন্যান্য সংকলকগুলির মধ্যে এটি কখন তৈরি হবে বলে আশা করা হচ্ছে :)
জ্যামি কুক

@ জোহানেস শ্যাব-লিটব আমার একই সমস্যা: একটি টেম্পলেট ফাংশনটিতে ডিফল্ট টাইপের স্পিরিচ করার কোনও সম্ভাবনা নেই। আমি ডিফল্ট ধরণের ( doubleআমার ক্ষেত্রে) ফাংশনটির সুস্পষ্ট ইনস্ট্যান্টেশন দ্বারা সমাধান করেছি। সম্ভবত এটি "জেনারেল" নয়, তবে এই অনুশীলনের সাথে কোনও অসুবিধা আছে কি? ধন্যবাদ।
জ্যাকলান্টারন

নিম্নলিখিত কোডগুলি error: invalid conversion from ‘int’ to ‘int*’কোনও ত্রুটির সাথে যেমন কোনও ধারণা কেন সংকলন করতে ব্যর্থ হয়েছে : Iterator beg, Iterator end, Comp c = Comp ()) d std :: সাজান (ভিক্ষা, শেষ, গ); main int main () d std :: অ্যারে <int, 5> আর {5,2,21,7,4}; my_sort (ar.begin (), ar.end ()); } `
লুক পিটারসন

36

সি ++ টেম্পলেটগুলির উদ্ধৃতি দিতে : সম্পূর্ণ গাইড (পৃষ্ঠা 207):

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


সহজ এবং সংক্ষিপ্ত :)
ইনকুসিটিভ

17

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

Arak:

struct S { 
    template <class R = int> R get_me_R() { return R(); } 
};

হতে পারে:

struct S {
    template <class R> R get_me_R() { return R(); } 
    int get_me_R() { return int(); }
};

আমার নিজের:

template <int N = 1> int &increment(int &i) { i += N; return i; }

হতে পারে:

template <int N> int &increment(int &i) { i += N; return i; }
int &increment(int &i) { return increment<1>(i); }

litb:

template<typename Iterator, typename Comp = std::less<Iterator> >
void sort(Iterator beg, Iterator end, Comp c = Comp())

হতে পারে:

template<typename Iterator>
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>())

template<typename Iterator, typename Comp >
void sort(Iterator beg, Iterator end, Comp c = Comp())

স্ট্রোভস্ট্রুপের:

template <class T, class U = double>
void f(T t = 0, U u = 0);

হতে পারে:

template <typename S, typename T> void f(S s = 0, T t = 0);
template <typename S> void f(S s = 0, double t = 0);

যা আমি নিম্নলিখিত কোড দিয়ে প্রমাণ করেছি:

#include <iostream>
#include <string>
#include <sstream>
#include <ctype.h>

template <typename T> T prettify(T t) { return t; }
std::string prettify(char c) { 
    std::stringstream ss;
    if (isprint((unsigned char)c)) {
        ss << "'" << c << "'";
    } else {
        ss << (int)c;
    }
    return ss.str();
}

template <typename S, typename T> void g(S s, T t){
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name()
        << ">(" << s << "," << prettify(t) << ")\n";
}


template <typename S, typename T> void f(S s = 0, T t = 0){
    g<S,T>(s,t);
}

template <typename S> void f(S s = 0, double t = 0) {
    g<S,double>(s, t);
}

int main() {
        f(1, 'c');         // f<int,char>(1,'c')
        f(1);              // f<int,double>(1,0)
//        f();               // error: T cannot be deduced
        f<int>();          // f<int,double>(0,0)
        f<int,char>();     // f<int,char>(0,0)
}

মুদ্রিত আউটপুটটি প্রতিটি কলের চ-এর মন্তব্যের সাথে মেলে এবং মন্তব্য-আউট কল প্রত্যাশার মতো সংকলন করতে ব্যর্থ।

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


@ স্টিভ: সুতরাং ডিমটি মুরগির চেয়ে দ্রুত চলছিল? :) আকর্ষণীয়। ধন্যবাদ।
আরমান

1
সম্ভবত those জিনিসগুলির মধ্যে একটি মাত্র। সি ++ মানীকরণ প্রক্রিয়াটি অংশে ধীরে ধীরে চলবে যাতে লোকেরা বুঝতে পারে যে কখন স্ট্যান্ডার্ডের অন্য কোথাও সুযোগ বা অসুবিধা সৃষ্টি হয়। সমস্যাগুলি আশা করা যায় যে খসড়া মানটি যখন তারা একটি দ্বন্দ্ব বা দ্বিধাগ্রস্থতা দেখায় তখন তারা মানদণ্ডের মান প্রয়োগ করে তারা কার্যকর হয়। আগে অনুমতি দেওয়া হয়নি এমন জিনিসগুলিকে অনুমতি দেওয়ার সুযোগগুলি, এমন কাউকে ভরসা করুন যে কোডটি লিখতে চায় তা দেখে যে এটি আর অবৈধ হওয়ার দরকার নেই ...
স্টিভ জেসোপ

2
আপনার জন্য আরও একটি: template<typename T = void> int SomeFunction();। এখানে টেমপ্লেট প্যারামিটারটি কখনও ব্যবহার করা হয় না এবং বাস্তবে ফাংশনটি কখনও বলা হয় না; এটি উল্লেখ করা হয় শুধুমাত্র জায়গা একটি decltypeবা sizeof। নামটি ইচ্ছাকৃতভাবে অন্য ফাংশনের নামের সাথে মেলে তবে এটি একটি টেমপ্লেট এর অর্থ সংকলকটি উপস্থিত থাকলে ফ্রি ফাংশনটি পছন্দ করবে। দুটি ফাংশন সংজ্ঞা অনুপস্থিত যেখানে ডিফল্ট আচরণ প্রদান করতে SFINAE এ ব্যবহৃত হয়।
টম

4

উইন্ডোজে, ভিজ্যুয়াল স্টুডিওর সমস্ত সংস্করণ সহ আপনি এই ত্রুটি ( C4519 ) কে একটি সতর্কবার্তে রূপান্তর করতে পারেন বা এটি এটিকে অক্ষম করতে পারেন:

#ifdef  _MSC_VER
#pragma warning(1 : 4519) // convert error C4519 to warning
// #pragma warning(disable : 4519) // disable error C4519
#endif

আরও বিশদ এখানে দেখুন


1
মনে রাখবেন, এটি "ডিফল্ট টেম্পলেট আর্গুমেন্টগুলি কেবলমাত্র কোনও শ্রেণীর টেম্পলেটে অনুমোদিত" বার্তাটি অক্ষম করে, এটি আসলে টেমপ্লেট ইনস্ট্যান্টেশন প্রক্রিয়া সরবরাহিত মানটিকে ব্যবহার করে না। এর জন্য ভিএস ২০১৩ (বা অন্য যে কোনও সংকলক সি ++ ১১ টি ত্রুটি 226 "ফাংশন টেম্পলেটগুলির জন্য ডিফল্ট টেম্পলেট আর্গুমেন্ট" সম্পন্ন করেছে) প্রয়োজন
পিত্তজক

1

আমি যা ব্যবহার করি তা পরবর্তী কৌশল:

বলুন আপনি এর মতো ফাংশন করতে চান:

template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
    E one(1);
    array.add( one );
}

আপনাকে অনুমতি দেওয়া হবে না, তবে আমি পরবর্তী উপায়ে করব:

template <typename T>
struct MyArray_t {
void add(T i) 
{
    // ...
}
};

template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
    /*static - as you wish */ ARR_E* parr_;
    void doStuff(); /* do not make this one static also, MSVC complains */
};

template <typename E, typename ARR_E>
void worker<E, ARR_E>::doStuff()
{
    E one(1);
    parr_->add( one );
}

সুতরাং আপনি এইভাবে এটি ব্যবহার করতে পারেন:

MyArray_t<int> my_array;
worker<int> w;
w.parr_ = &arr;
w.doStuff();

আমরা দেখতে পাচ্ছি যে পরিষ্কারভাবে দ্বিতীয় প্যারামিটার সেট করার দরকার নেই। এটি কারও পক্ষে কাজে লাগবে।


এটি অবশ্যই কোনও উত্তর নয়।
পপি

@ ডিএডএমজি - আপনি কেন ব্যাখ্যা করতে পারেন? আমরা সমস্ত সি ++ টেম্পলেট গুরু নই। ধন্যবাদ।
কেভ

এটি একটি কার্যনির্বাহী যা বেশ ঝরঝরে কিন্তু এটি আপনার পছন্দসই সমস্ত মামলা কভার করবে না। উদাহরণস্বরূপ আপনি কীভাবে এটি কোনও কনস্ট্রাক্টরে প্রয়োগ করবেন?
টিবেরিউ সাভিন

@ টিবেরিউসভিন - যদি আমি আপনাকে সঠিকভাবে বুঝতে পারি তবে আপনি এটির মতো করতে পারেন: টেম্পলেট <টাইপনেম ই, টাইপনাম এআরআর_ই> কর্মী <ই, এআরআর_ই> :: কর্মী (এআরআর_ই * পারর) r পারর_ = পারর; }। এবং তারপরে এটির মতো ব্যবহার করুন: কর্মী <int> ডাব্লু 2 (& আমার_আরে);
আলারিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.