সি ++ তে রেফারেন্স দিয়ে যাওয়ার সময় কোনও প্যারামিটারে ডিফল্ট মান


116

আমরা রেফারেন্স দ্বারা প্যারামিটারটি পাস করার সময় কোনও ফাংশনের প্যারামিটারকে একটি ডিফল্ট মান দেওয়া কি সম্ভব? সি ++ এ

উদাহরণস্বরূপ, যখন আমি কোনও ফাংশন যেমন ঘোষণা করার চেষ্টা করি:

virtual const ULONG Write(ULONG &State = 0, bool sequence = true);

আমি যখন এটি করি এটি একটি ত্রুটি দেয়:

ত্রুটি C2440: 'ডিফল্ট আর্গুমেন্ট': 'কনস্ট ইনট' থেকে 'স্বাক্ষরবিহীন লম্বা'তে রূপান্তর করতে পারে না এবং' কনস্ট 'নয় এমন একটি রেফারেন্স অ-লভ্যুতে আবদ্ধ হতে পারে না


96
করুণার সাথে, আমরা গুগল স্টাইল গাইড দ্বারা আবদ্ধ নই।

23
"এটি করবেন না Google গুগল স্টাইল গাইড (এবং অন্যরা) রেফারেন্স সহ নন-কনস্ট পাস নিষিদ্ধ করেছেন" আমি মনে করি স্টাইল গাইডগুলিতে অনেকগুলি বিষয়গত অংশ রয়েছে বলে জানা যায়। এটি তাদের মধ্যে একটির মতো দেখাচ্ছে।
জোহানেস স্কাউব - লিটব

13
WxWidgets style guide says "don't use templates" and they have good reasons<- স্ক্রু std :: ভেক্টর, আমি বলছি
জোহানেস স্কাউব - লিটব

7
@ জেফামফোন: গুগল স্টাইল গাইড স্ট্রিম ব্যবহার না করার কথাও বলেছে। আপনি কি এগুলি এড়িয়ে চলা পরামর্শ দেবেন?
rlbond

10
একটি হাতুড়ি একটি স্ক্রু ড্রাইভার রাখার জন্য একটি ভয়ঙ্কর সরঞ্জাম, তবে এটি নখ দিয়ে বেশ ব্যবহারযোগ্য। আপনি যে কোনও বৈশিষ্ট্যটির অপব্যবহার করতে পারবেন তা কেবল আপনাকে সম্ভাব্য ক্ষতির বিষয়ে সতর্ক করতে হবে তবে এর ব্যবহার নিষিদ্ধ করবে না।
ডেভিড রদ্রিগেজ - ড্রিবিস

উত্তর:


102

আপনি এটি একটি কনস্ট্যান্ড রেফারেন্সের জন্য করতে পারেন, তবে অ-কনস্ট্যান্ডের জন্য নয়। এটি কারণ সি ++ অস্থায়ী (এই ক্ষেত্রে ডিফল্ট মান) অ-কনস্ট্যান্ট রেফারেন্সের সাথে আবদ্ধ হতে দেয় না।

এটির একটি উপায় হ'ল ডিফল্ট হিসাবে প্রকৃত উদাহরণটি ব্যবহার করা হবে:

static int AVAL = 1;

void f( int & x = AVAL ) {
   // stuff
} 

int main() {
     f();       // equivalent to f(AVAL);
}

তবে এটি ব্যবহারিক ব্যবহার সীমিত।


যদি আমি এটি কনস্ট্যান্ট করি তবে এটি কি আমাকে ফাংশনে আলাদা ঠিকানা দেওয়ার অনুমতি দেবে? বা রাষ্ট্রের ঠিকানা সর্বদা 0 এবং এত অর্থহীন হবে?

আপনি যদি রেফারেন্স ব্যবহার করছেন তবে আপনি ঠিকানাগুলি পাস করছেন না।

3
বুস্ট :: অ্যারে রেসকিউ অকার্যকর চ (ইনট & এক্স = বুস্ট :: অ্যারে <ইনট, 1> () [0]) {..} :)
জোহানেস স্কাউব - লিটব

1
ঠিকানা না হলে আসলে কি পাস হচ্ছে?

2
@ সনি একটি রেফারেন্স। এটিকে ঠিকানা হিসাবে ভাবতে পারা যায় না। আপনি যদি ঠিকানা চান, একটি পয়েন্টার ব্যবহার করুন।

32

এটি ইতিমধ্যে আপনার উত্তরের প্রত্যক্ষ মন্তব্যের মধ্যে একটিতে বলা হয়েছে, তবে কেবল এটি সরকারীভাবে বর্ণনা করার জন্য। আপনি যা ব্যবহার করতে চান তা একটি ওভারলোড:

virtual const ULONG Write(ULONG &State, bool sequence);
inline const ULONG Write()
{
  ULONG state;
  bool sequence = true;
  Write (state, sequence);
}

ফাংশন ওভারলোডগুলি ব্যবহারের অতিরিক্ত সুবিধাও রয়েছে। প্রথমত আপনি যে কোনও যুক্তিটি ডিফল্ট করতে পারেন:

class A {}; 
class B {}; 
class C {};

void foo (A const &, B const &, C const &);
void foo (B const &, C const &); // A defaulted
void foo (A const &, C const &); // B defaulted
void foo (C const &); // A & B defaulted etc...

উদ্ভূত শ্রেণিতে ভার্চুয়াল ফাংশনগুলিতে ডিফল্ট যুক্তিগুলি পুনরায় সংজ্ঞায়িত করা সম্ভব যা ওভারলোডিং এড়ানো হয়:

class Base {
public:
  virtual void f1 (int i = 0);  // default '0'

  virtual void f2 (int);
  inline void f2 () {
    f2(0);                      // equivalent to default of '0'
  }
};

class Derived : public Base{
public:
  virtual void f1 (int i = 10);  // default '10'

  using Base::f2;
  virtual void f2 (int);
};

void bar ()
{
  Derived d;
  Base & b (d);
  d.f1 ();   // '10' used
  b.f1 ();   // '0' used

  d.f2 ();   // f1(int) called with '0' 
  b.f2 ();   // f1(int) called with '0
}

কেবলমাত্র একটি পরিস্থিতি রয়েছে যেখানে একটি ডিফল্ট সত্যই ব্যবহার করা প্রয়োজন এবং এটি কনস্ট্রাক্টরের উপর। অন্য একজনের কাছ থেকে একজন কনস্ট্রাক্টরকে কল করা সম্ভব নয় এবং সুতরাং এই কৌশলটি সে ক্ষেত্রে কার্যকর হয় না।


19
কিছু লোক মনে করেন একটি ডিফল্ট-পরম ওভারলোডের দৈত্যের গুণকের চেয়ে কম ভয়ঙ্কর।
মিঃ বয়

2
হতে পারে শেষে, আপনি পরামর্শ: d.f2(); // f2(int) called with '0' b.f2(); // f2(int) called with '0'
পাইট্রো

4
শেষ বিবৃতিতে: সি ++ 11 থেকে, আপনি কোড নকল এড়াতে অন্যের কাছ থেকে একজন কনস্ট্রাক্টরকে কল করতে ডেলিগেট কনস্ট্রাক্টর ব্যবহার করতে পারেন।
ফ্রেড শোয়েন

25

Optionচ্ছিক আর্গুমেন্ট সরবরাহ করার এখনও পুরানো সি উপায় রয়েছে: একটি পয়েন্টার যা উপস্থিত না থাকলে নুল হতে পারে:

void write( int *optional = 0 ) {
    if (optional) *optional = 5;
}

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

11

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

template<typename T> class ByRef {
public:
    ByRef() {
    }

    ByRef(const T value) : mValue(value) {
    }

    operator T&() const {
        return((T&)mValue);
    }

private:
    T mValue;
};

তারপরে আপনি সক্ষম হবেন:

virtual const ULONG Write(ULONG &State = ByRef<ULONG>(0), bool sequence = true);

ByRefজীবন্ত, স্মৃতি- জ্ঞানহীনদের ইনস্ট্যান্টেশন কোথায় ? এটি কি কোনও অস্থায়ী বস্তু নয় যা কিছু সুযোগ রেখে (ধ্বংসকারীর মতো) ধ্বংস হয়ে যাবে?
অ্যান্ড্রু চিউং

1
@ অ্যান্ড্রুচিয়ং এর সম্পূর্ণ অভিপ্রায়টি হ'ল স্পটটি নির্মাণ করা এবং লাইনটি সম্পূর্ণ হওয়ার পরে ধ্বংস হওয়া। এটি কলটির সময়কালের জন্য একটি রেফারেন্স প্রকাশ করার একটি মাধ্যম যাতে কোনও ডিফল্ট পরামিতি সরবরাহ করা যায় এমনকি যখন এটি কোনও রেফারেন্স আশা করে। এই কোডটি একটি সক্রিয় প্রকল্পে এবং প্রত্যাশার মতো ফাংশনে ব্যবহৃত হয়।
মাইক ওয়েয়ার

7

না, এটা সম্ভব নয়।

রেফারেন্স দ্বারা পাস করার অর্থ এই ফাংশনটি প্যারামিটারের মান পরিবর্তন করতে পারে। যদি প্যারামিটারটি কলার সরবরাহ না করে এবং ডিফল্ট ধ্রুবক থেকে আসে তবে ফাংশনটি পরিবর্তনের কথা কী?


3
Traditionalতিহ্যবাহী ফরট্রান পদ্ধতিতে 0 এর মান পরিবর্তন করা হত তবে এটি সি ++ তে হয় না।
ডেভিড থর্নলি

7

রেফারেন্স দ্বারা একটি যুক্তি পাস করার দুটি কারণ রয়েছে: (১) পারফরম্যান্সের জন্য (যে ক্ষেত্রে আপনি কনস্টের্ট রেফারেন্স দিয়ে পাস করতে চান) এবং (২) কারণ আপনাকে ফাংশনের অভ্যন্তরে যুক্তির মান পরিবর্তন করার দক্ষতা প্রয়োজন need

আমি অত্যন্ত সন্দেহ করি যে আধুনিক স্থাপত্যগুলিতে স্বাক্ষরবিহীন দীর্ঘ অতিক্রম করা আপনাকে খুব কমিয়ে দিচ্ছে। সুতরাং আমি ধরে নিচ্ছি যে আপনি Stateপদ্ধতির অভ্যন্তরের মান পরিবর্তন করতে চাইছেন। 0সংকলকটি অভিযোগ করছে কারণ ধ্রুবকটি পরিবর্তন করা যায় না, কারণ এটি একটি মূল্য (ত্রুটি বার্তায় "অ-মূল্যবান") এবং অপরিবর্তনীয় (const ত্রুটির বার্তায়)।

সরল কথায় বলতে গেলে, আপনি এমন একটি পদ্ধতি চান যা পাস করা যুক্তিটি পরিবর্তন করতে পারে তবে ডিফল্টরূপে আপনি এমন একটি যুক্তি পাস করতে চান যা পরিবর্তন করতে পারে না।

এটিকে অন্য উপায়ে বলতে গেলে, অ- constরেফারেন্সগুলিকে প্রকৃত ভেরিয়েবলগুলি উল্লেখ করতে হয়। ফাংশন সিগনেচারের ডিফল্ট মান ( 0) একটি আসল পরিবর্তনশীল নয়। আপনি একই সমস্যার মধ্যে চলেছেন:

struct Foo {
    virtual ULONG Write(ULONG& State, bool sequence = true);
};

Foo f;
ULONG s = 5;
f.Write(s); // perfectly OK, because s is a real variable
f.Write(0); // compiler error, 0 is not a real variable
            // if the value of 0 were changed in the function,
            // I would have no way to refer to the new value

যদি আপনি আসলে Stateপদ্ধতির অভ্যন্তরে পরিবর্তন করতে চান না তবে আপনি কেবল এটিকে এটিকে পরিবর্তন করতে পারেন const ULONG&। তবে আপনি এটি থেকে কোনও বড় পারফরম্যান্স সুবিধা পাবেন না, তাই আমি এটিকে একটি অ-রেফারেন্সে পরিবর্তনের পরামর্শ দেব ULONG। আমি লক্ষ্য করেছি যে আপনি ইতিমধ্যে একটি ফিরে আসছেন ULONG, এবং আমার কাছে একটি লুক্কায়িত সন্দেহ আছে যে Stateকোনও মান প্রয়োজনীয় সংশোধন করার পরে এর মান value কোন ক্ষেত্রে আমি পদ্ধতিটি কেবল তাই ঘোষণা করব:

// returns value of State
virtual ULONG Write(ULONG State = 0, bool sequence = true);

আপনি কী লিখছেন বা কোথায় লিখছেন তা অবশ্যই নিশ্চিত নই। তবে এটি অন্য সময়ের জন্য আরেকটি প্রশ্ন।


6

আপনি একই কারণে ডিফল্ট প্যারামিটারের জন্য ধ্রুবক আক্ষরিক ব্যবহার করতে পারবেন না কারণ আপনি ফাংশন কলের পরামিতি হিসাবে এটি ব্যবহার করতে পারবেন না। রেফারেন্স মানগুলির একটি ঠিকানা থাকতে হবে, ধ্রুবক রেফারেন্স মানগুলির প্রয়োজন নেই (যেমন তারা আর-মান বা ধ্রুবক আক্ষরিক হতে পারে)।

int* foo (int& i )
{
   return &i;
}

foo(0); // compiler error.

const int* bar ( const int& i )
{
   return &i;
}

bar(0); // ok.

আপনার ডিফল্ট মানটির একটি ঠিকানা রয়েছে তা নিশ্চিত করুন এবং আপনি ভাল আছেন।

int null_object = 0;

int Write(int &state = null_object, bool sequence = true)
{
   if( &state == &null_object )
   {
      // called with default paramter
      return sequence? 1: rand();
   }
   else
   {
      // called with user parameter
      state += sequence? 1: rand();
      return state;
   }
}

আমি এই প্যাটার্নটি কয়েকবার ব্যবহার করেছি যেখানে আমার একটি প্যারামিটার ছিল যা ভেরিয়েবল বা নাল হতে পারে। নিয়মিত পদ্ধতির মধ্যে ব্যবহারকারীকে পয়েন্টারে পাস করার বিষয়টি হয়। তারা যদি মানটি পূরণ না করতে চায় তবে তারা একটি নাল পয়েন্টারে পাস করে। আমি অবজেক্ট অ্যাপ্রোচ বাতিল করতে চাই। এটি কলি কোডকে ভয়ঙ্করভাবে জটিল না করে কলারদের জীবনকে আরও সহজ করে তোলে।


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

1

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


2
ডিফল্ট মানগুলি "ধ্রুবক হিসাবে মূল্যায়ন করা হয় না"।

1

অন্য উপায় নিম্নলিখিত হতে পারে:

virtual const ULONG Write(ULONG &State, bool sequence = true);

// wrapper
const ULONG Write(bool sequence = true)
{
   ULONG dummy;
   return Write(dummy, sequence);
}

তাহলে নিম্নলিখিত কলগুলি সম্ভব:

ULONG State;
object->Write(State, false); // sequence is false, "returns" State
object->Write(State); // assumes sequence = true, "returns" State
object->Write(false); // sequence is false, no "return"
object->Write(); // assumes sequence = true, no "return"

1
void f(const double& v = *(double*) NULL)
{
  if (&v == NULL)
    cout << "default" << endl;
  else
    cout << "other " << v << endl;
}

এটা কাজ করে। মূলত, এটি NUL নির্দেশক রেফারেন্সটি পরীক্ষা করার জন্য ভ্যালু-এট-রেফারেন্সটি অ্যাক্সেস করা (যৌক্তিকভাবে কোনও NULL- রেফারেন্স নেই, কেবলমাত্র আপনি যা নির্দেশ করেন সেটি নুল হয়)। ওপরে, আপনি যদি কিছু লাইব্রেরি ব্যবহার করছেন যা "রেফারেন্সগুলি" ব্যবহার করে তবে সাধারণত লাইব্রেরির নির্দিষ্ট রেফারেন্স ভেরিয়েবলগুলির জন্য একইভাবে কিছু করার জন্য "isNull ()" এর মতো কিছু API থাকবে। এবং এই জাতীয় ক্ষেত্রে এপিআইগুলি ব্যবহার করার পরামর্শ দেওয়া হচ্ছে।
পরশ্রিশ

1

ওওর ক্ষেত্রে ... বলতে গেলে কোনও প্রদত্ত শ্রেণি রয়েছে এবং "ডিফল্ট" এর অর্থ এই ডিফল্ট (মান) অবশ্যই স্বতঃস্ফূর্তভাবে ঘোষিত হওয়া অবশ্যই একটি ডিফল্ট প্যারামিটার হিসাবে ইউএসডি হতে পারে প্রাক্তন:

class Pagination {
public:
    int currentPage;
    //...
    Pagination() {
        currentPage = 1;
        //...
    }
    // your Default Pagination
    static Pagination& Default() {
        static Pagination pag;
        return pag;
    }
};

আপনার পদ্ধতিতে ...

 shared_ptr<vector<Auditoria> > 
 findByFilter(Auditoria& audit, Pagination& pagination = Pagination::Default() ) {

এই সমাধানগুলি বেশ উপযুক্ত, যেহেতু এই ক্ষেত্রে, "গ্লোবাল ডিফল্ট পৃষ্ঠাগুলি" একটি একক "রেফারেন্স" মান। রানওটাইমে ডিফল্ট মানগুলি "গাবল-স্তর" কনফিগারেশন যেমন: ব্যবহারকারী পৃষ্ঠাগুলি ন্যাভিগেশন অগ্রাধিকার ইত্যাদির মতো পরিবর্তন করার ক্ষমতাও আপনার থাকবে ..


1

রাজ্যের জন্য কনস্ট কোয়ালিফায়ার দিয়ে এটি সম্ভব:

virtual const ULONG Write(const ULONG &State = 0, bool sequence = true);

কনস্টের রেফ হিসাবে দীর্ঘ সময় অতিবাহিত করা অর্থহীন এবং এমনকি হাস্যকর এবং ওপি যা চায় তা অর্জন করে না।
জিম বাল্টার


0

এর জন্য বরং নোংরা কৌশলও রয়েছে:

virtual const ULONG Write(ULONG &&State = 0, bool sequence = true);

এক্ষেত্রে আপনাকে এটিকে কল করতে হবে std::move:

ULONG val = 0;
Write(std::move(val));

এটি কেবল কিছু মজার কাজ, আমি সম্পূর্ণরূপে এটি বাস্তব কোড ব্যবহার করে সুপারিশ করি না!


0

আমার এটির জন্য একঝাঁক কাজ রয়েছে, এর জন্য ডিফল্ট মানের জন্য নিম্নলিখিত উদাহরণটি দেখুন int&:

class Helper
{
public:
    int x;
    operator int&() { return x; }
};

// How to use it:
void foo(int &x = Helper())
{

}

আপনি এটি যে কোনও তুচ্ছ ডেটা ধরণের জন্য চান যেমন করতে পারেন bool, double...


0

2 ওভারলোড ফাংশনগুলি সংজ্ঞায়িত করুন।

virtual const ULONG Write(ULONG &State, bool sequence = true);

virtual const ULONG Write(bool sequence = true)
{
    int State = 0;
    return Write(State, sequence);
}

-3

ভার্চুয়াল কনস্ট ইউলং লিখুন (উলং এবং রাজ্য = 0, বুল সিকোয়েন্স = সত্য);

উত্তরটি বেশ সহজ এবং আমি ব্যাখ্যা করার ক্ষেত্রে এতটা ভাল নই তবে আপনি যদি কোনও ডিফল্ট মান একটি অ-কনসেন্ট প্যারামিটারে দিতে চান যা সম্ভবত এই ফাংশনে সংশোধন করা হবে এটি এটি ব্যবহার করা এই:

virtual const ULONG Write(ULONG &State = *(ULONG*)0, bool sequence =
> true);

3
একটি NUL পয়েন্টার ডিফারিং অবৈধ। এটি কিছু ক্ষেত্রে কার্যকর হতে পারে তবে এটি অবৈধ। এখানে আরও পড়ুন parashift.com/c++-faq-lite/references.html#faq-8.7
Spo1ler
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.