সি ++ এ ডাবল নেগেশন


124

আমি সবেমাত্র একটি বিশাল বিশাল কোড বেস সহ একটি প্রকল্পে এসেছি।

আমি বেশিরভাগ সি ++ এর সাথে কাজ করছি এবং তারা যে কোডটি লিখেছেন তাদের অনেকগুলিই তাদের বুলিয়ান যুক্তির জন্য দ্বিগুণ প্রত্যাখ্যান ব্যবহার করে।

 if (!!variable && (!!api.lookup("some-string"))) {
       do_some_stuff();
 }                                   

আমি জানি এই ছেলেরা বুদ্ধিমান প্রোগ্রামার, এগুলি স্পষ্টতই দুর্ঘটনাক্রমে তারা করছে না।

আমি কোন পাকা সি ++ বিশেষজ্ঞ নই, কেন তারা এটি করছে তা সম্পর্কে আমার একমাত্র অনুমান যে তারা একেবারে ইতিবাচক করতে চান যে মূল্য নির্ধারণ করা হচ্ছে এটিই আসল বুলিয়ান প্রতিনিধিত্ব। সুতরাং তারা এটিকে প্রত্যাখ্যান করে, আবার এটিকে আবার প্রত্যাখ্যান করে এটির আসল বুলিয়ান মানটিতে ফিরে পেতে।

এটি কি সঠিক, না আমি কিছু মিস করছি?


4
এখানে চেক করুন, ইতিমধ্যে জিজ্ঞাসা করা হয়েছে, হয় !! সি ++ এ বুলে রূপান্তর করার নিরাপদ উপায়?
üzgür

এই বিষয়টি এখানে আলোচনা করা হয়েছে
ডিমা

উত্তর:


121

এটি বুলে রূপান্তরিত করার কৌশল।


19
আমি মনে করি এটি স্পষ্টভাবে কাস্ট করুন (বুল) আরও পরিষ্কার হবে, কেন এই কৌশলটি ব্যবহার করুন !!, কারণ এটি টাইপিং কম?
বায়ান হুয়াং

27
তবে এটি সি ++ বা আধুনিক সিতে অর্থহীন, বা যেখানে ফলাফলটি কেবলমাত্র বুলিয়ান অভিব্যক্তিতে ব্যবহৃত হয় (প্রশ্ন হিসাবে)। বুলিয়ান ভেরিয়েবলগুলি boolব্যতীত 1এবং অন্যান্য মানগুলি সংরক্ষণ করা এড়াতে আমাদের কোনও প্রকার না থাকলে এটি কার্যকর ছিল 0
মাইক সিমুর

6
@lzprgmr: সুস্পষ্ট কাস্ট এমএসভিসিতে একটি "পারফরম্যান্স সতর্কতা" সৃষ্টি করে। সমস্যাটি ব্যবহার করা !!বা !=0সমাধান করা এবং দুজনের মধ্যে আমি প্রাক্তন ক্লিনারটি খুঁজে পাই (যেহেতু এটি আরও বেশি ধরণের ধরণের ক্ষেত্রে কাজ করবে)। এছাড়াও আমি সম্মত হলাম যে প্রশ্নে কোডটি ব্যবহার করার কোনও কারণ নেই।
ইয়াকভ গালকা

6
@ নলডোরিন, আমি মনে করি এটি পাঠযোগ্যতার উন্নতি করে - আপনি যদি এর অর্থ কী জানেন তবে এটি সহজ, ঝরঝরে এবং যৌক্তিক।
jwg

19
উন্নত? রক্তাক্ত নরক ... আপনি যা কিছু ধূমপান করছেন তা আমাকে কিছু দিন।
নলডোরিন

73

এটি কিছু প্রসঙ্গে প্রকৃতপক্ষে একটি খুব দরকারী আইডিয়াম। এই ম্যাক্রোগুলি নিন (লিনাক্স কার্নেল থেকে উদাহরণস্বরূপ)। জিসিসির জন্য, তারা নিম্নলিখিত হিসাবে প্রয়োগ করা হয়েছে:

#define likely(cond)   (__builtin_expect(!!(cond), 1))
#define unlikely(cond) (__builtin_expect(!!(cond), 0))

তাদের কেন এটি করতে হবে? জিসিসি এর __builtin_expectপ্যারামিটারগুলিকে হিসাবে বিবেচনা করে longএবং না bool, তাই রূপান্তর কিছু প্রকারের হওয়া দরকার। যেহেতু তারা জানে না যে condতারা কখন এই ম্যাক্রোগুলি লিখছেন, তাই কেবল !!প্রবাদটি ব্যবহার করা সবচেয়ে সাধারণ ।

তারা 0 এর সাথে তুলনা করে সম্ভবত একই জিনিসটি করতে পারে, তবে আমার মতে, ডাবল-নেগ্রেশন করাটা আসলে আরও সহজবোধ্য, যেহেতু এটি সি'র কাছাকাছি-বুলের নিকটতম।

এই কোডটি সি ++ তেও ব্যবহার করা যেতে পারে ... এটি সর্বনিম্ন-সাধারণ-ডিনোমিনেটর জিনিস। যদি সম্ভব হয় তবে সি এবং সি ++ উভয় ক্ষেত্রে যা কাজ করে তা করুন।


আমি মনে করি এটি যখন আপনি এটির মাধ্যমে চিন্তা করেন তখন এটি অনেক অর্থবোধ করে। আমি প্রতিটি উত্তর পড়িনি, তবে মনে হচ্ছে রূপান্তর প্রক্রিয়াটি নির্দিষ্ট করা হয়নি। যদি আমাদের কাছে 2 বিট উচ্চ মানের একটি মান থাকে এবং আমরা কেবল একটি বিট উঁচু এমন মানটি দিয়ে থাকি তবে আমাদের একটি শূন্য-মান হবে না। একটি বুলিয়ান রূপান্তর হিসাবে একটি শূন্য-না-মান ফলাফলের আলোচনা করা (এটি যদি শূন্য হয় তবে মিথ্যা, অন্যথায় সত্য)। তারপরে আবার উপেক্ষা করার ফলে এমন একটি বুলিয়ান তৈরি হয় যা আসল সত্যকে উপস্থাপন করে।
জোয়ে কারসন

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

51

কোডাররা মনে করেন যে এটি অপারেন্ডকে বোলে রূপান্তরিত করবে, কিন্তু && এর অপারেন্ডগুলি ইতিমধ্যে স্পষ্টভাবে বোলে রূপান্তরিত হয়েছে, এটি একেবারে অপ্রয়োজনীয়।


14
ভিজ্যুয়াল সি ++ এই কৌশলটি ছাড়াই কিছু ক্ষেত্রে নিখরচায় একটি পারফরম্যান্স দেয়।
কিরিল ভি লিয়াডভিনস্কি

1
আমি মনে করি কোডে অকেজো সতর্কতার আশেপাশে কাজ করার চেয়ে সতর্কতাটি কেবল অক্ষম করা ভাল।
রুসলান

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

12

এটি রচনা (পরিবর্তনশীল! = 0) এড়ানোর কৌশল ie

এটির মতো আইএমও কোডের সিস্টেমগুলিতে কোনও স্থান নেই যা বজায় রাখা দরকার - কারণ এটি তাত্ক্ষণিকভাবে পঠনযোগ্য কোড নয় (এজন্য প্রথম স্থানে প্রশ্ন)।

কোড অবশ্যই সুস্পষ্ট হতে হবে - অন্যথায় আপনি ভবিষ্যতের জন্য সময় debtণের উত্তরাধিকার রেখে চলেছেন - কারণ অযথা অবিচ্ছিন্নভাবে কিছু বোঝার জন্য সময় লাগে।


8
একটি কৌশল সম্পর্কে আমার সংজ্ঞা এমন একটি বিষয় যা প্রত্যেকে প্রথম পড়তে বুঝতে পারে না। কিছু যেটির জন্য নির্ণয়ের প্রয়োজন তা একটি কৌশল। ভয়াবহ কারণ! অপারেটর ওভারলোড হতে পারে ...
রিচার্ড হ্যারিসন

6
@ অরল্যান্ডু 63৩: সাধারণ টাইপকাস্টিং হ'ল bool(expr): এটি সঠিক কাজ করে এবং প্রত্যেকে প্রথম দর্শনে অভিপ্রায়টি বুঝতে পারে। !!(expr)দ্বৈত অবহেলা, যা দুর্ঘটনাক্রমে বিলে রূপান্তরিত হয় ... এটি সাধারণ নয়।
অ্যাড্রিয়েন প্লিসন

12

হ্যাঁ এটি সঠিক এবং না আপনি কিছু মিস করছেন না। !!হ'ল বিলে রূপান্তর। আরও আলোচনার জন্য এই প্রশ্নটি দেখুন ।


9

এটি একটি সংকলক সতর্কবার্তাটি সাইড-স্টেপ করে। এটা চেষ্টা কর:

int _tmain(int argc, _TCHAR* argv[])
{
    int foo = 5;
    bool bar = foo;
    bool baz = !!foo;
    return 0;
}

'বার' লাইনটি এমএসভিসি ++ তে "সত্য" বা 'মিথ্যা' (পারফরম্যান্স সতর্কতা) "বলের জন্য জোর করে মান উত্পন্ন করে, তবে 'বাজ' লাইন জরিমানার মধ্য দিয়ে যায়।


1
সাধারণত উইন্ডোজ এপিআই-এ নিজেই মুখোমুখি হয়েছিলেন যা boolটাইপ সম্পর্কে জানেন না - সবকিছুই এন-এনড হিসাবে 0বা এনকোড করা 1আছে int
মার্ক রান্সম

4

অপারেটর! ওভারলোড?
যদি তা না হয় তবে তারা সম্ভবত কোনও সতর্কবার্তা না দিয়ে ভেরিয়েবলটিকে একটি বোলে রূপান্তর করার জন্য করছেন। এটি অবশ্যই জিনিসগুলি করার মানক উপায় নয়।


4

উত্তরাধিকার সি ডেভেলপারদের, কোন বুলিয়ান টাইপ ছিল তাই তারা প্রায়ই #define TRUE 1এবং #define FALSE 0এবং তারপর বুলিয়ান তুলনা জন্য নির্বিচারে সাংখ্যিক ধরনের তথ্য ব্যবহার করা হয়েছে। এখন আমাদের কাছে bool, অনেক সংকলক সংখ্যার প্রকারের এবং বুলিয়ান প্রকারের মিশ্রণ ব্যবহার করে নির্দিষ্ট ধরণের অ্যাসাইনমেন্ট এবং তুলনা করা হলে সতর্কতা প্রেরণ করবে। উত্তরাধিকারের কোড সহ কাজ করার পরে এই দুটি ব্যবহারের শেষ পর্যন্ত সংঘর্ষ হবে।

এই সমস্যাটি সমাধান করার জন্য, কিছু বিকাশকারী নীচের বুলিয়ান পরিচয় ব্যবহার করেন: যদি !num_valueফেরত দেয় ; অন্যথায়। যদি ফেরত দেয় ; অন্যথায়। একক অবহেলা রূপান্তর করতে যথেষ্ট ; তবে, বুলিয়ান এক্সপ্রেশনটির আসল ধারণাটি পুনরুদ্ধার করার জন্য দ্বিগুণ প্রত্যাখ্যান প্রয়োজনীয়।bool truenum_value == 0false!!num_valuebool falsenum_value == 0truenum_valuebool

এই প্যাটার্নটি একটি মূর্খতা হিসাবে পরিচিত , অর্থাত্ ভাষাটির সাথে পরিচিত লোকেরা সাধারণত এটি ব্যবহার করেন। অতএব, আমি এটিকে যতটুকু দেখব ততটা একটি অ্যান্টি-প্যাটার্ন হিসাবে দেখছি না static_cast<bool>(num_value)। কাস্টটি খুব ভালভাবে সঠিক ফলাফল দিতে পারে তবে কিছু সংকলক তারপরে একটি পারফরম্যান্স সতর্কতা প্রেরণ করে, তাই আপনাকে এখনও এটিকে সম্বোধন করতে হবে।

এটিকে সম্বোধনের অন্য উপায়টি হ'ল (num_value != FALSE),। আমি !!num_valueএটির সাথেও ঠিক আছি, তবে সব মিলিয়ে খুব কম শব্দাবলীর, আরও পরিষ্কার হতে পারে এবং দ্বিতীয়বার আপনি এটি দেখলে বিভ্রান্ত করছেন না।


2

!! আসল সি ++ এর সাথে লড়াই করতে ব্যবহার করা হয়েছিল যার বুলেট জাতীয় ধরণ ছিল না (যেমন সিও হয় নি)।


সমস্যার উদাহরণ:

অভ্যন্তরীণভাবে if(condition), conditionকিছু প্রকারের double, int, void*ইত্যাদির মূল্যায়ন করা প্রয়োজন , তবে boolএটি এখনও বিদ্যমান না বলে নয়।

বলুন একটি শ্রেণি বিদ্যমান int256(একটি 256 বিট পূর্ণসংখ্যার) এবং সমস্ত পূর্ণসংখ্যার রূপান্তর / কাস্টগুলি ওভারলোড হয়েছিল।

int256 x = foo();
if (x) ...

x"সত্য" বা অ-শূন্য কিনা তা পরীক্ষা করতে কিছু পূর্ণসংখ্যায় if (x)রূপান্তরিত xহয় এবং তা নির্ণয় করে যে intএটি শূন্য নয় কিনা । এর একটি সাধারণ ওভারলোড (int) xকেবলমাত্র এলএসবাইটের ফেরত দেয় xif (x)তখন কেবল এলএসবিটস এর পরীক্ষা করছিল x

তবে সি ++ এর !অপারেটর রয়েছে। একটি অতিরিক্ত লোড !xসাধারণত সমস্ত বিট মূল্যায়ন করবে x। সুতরাং ফিরে পেতে অ-উল্টানো যুক্তি if (!!x)ব্যবহার করা হয়।

রেফারেন্স কি সি ++ এর পুরানো সংস্করণগুলি `if ()` বিবৃতিতে শর্তটি মূল্যায়ন করার সময় কোনও শ্রেণীর `ইন্ট` অপারেটর ব্যবহার করেছিল?


1

মার্সিন যেমন উল্লেখ করেছেন, অপারেটর ওভারলোডিং চলছে কিনা তা ভালই লাগবে। অন্যথায়, সি / সি ++ এ আপনি নিম্নলিখিত বিষয়গুলির মধ্যে একটি করছেন তা বাদ দিয়ে কিছু যায় আসে না:

  • এর সাথে সরাসরি তুলনা true(বা সিতে TRUEম্যাক্রোর মতো কিছু ), যা প্রায়শই একটি খারাপ ধারণা। উদাহরণ স্বরূপ:

    if (api.lookup("some-string") == true) {...}

  • আপনি কেবল কিছু কঠোর 0/1 মান রূপান্তর করতে চান। সি ++ তে একটি কার্যনির্বাহী boolএই বিষয়টি স্পষ্টতই করবে (সেই বিষয়গুলির জন্য যা স্পষ্টত রূপান্তরিত হয় bool)। সিতে বা আপনি যদি একটি নন-বুল ভেরিয়েবলের সাথে ডিল করছেন, এটি এমন একটি মূর্খতা যা আমি দেখেছি, তবে আমি (some_variable != 0)নিজেই বিভিন্নটিকে পছন্দ করি।

আমি মনে করি একটি বৃহত বুলিয়ান অভিব্যক্তি প্রসঙ্গে এটি কেবল জিনিসগুলিকে বিশৃঙ্খলা করে।


1

যদি ভেরিয়েবল অবজেক্ট টাইপের হয় তবে এটির একটি থাকতে পারে! অপারেটরটিকে সংজ্ঞায়িত করা হয়েছে তবে কুলকে কাস্ট করা হয়নি (বা আরও বিভিন্ন শব্দার্থবিজ্ঞানের সাথে অন্তর্নিহিত একটি castালাই। অপারেটরকে কল করা দু'বার বিলে রূপান্তরিত করে যা এমনকি বিচিত্র ক্ষেত্রেও কাজ করে।


0

এটি সঠিক তবে সি তে এখানে অর্থহীন - 'যদি' এবং '&&' '' 'ছাড়া অভিব্যক্তির সাথে একইরকম আচরণ করবে।

আমার ধারণা, সি ++ এ করার কারণটি হ'ল '&&' ওভারলোড করা যায়। কিন্তু তারপর, তাই পারা '!', তাই এটি না সত্যিই আপনি ধরনের কোড দিকে না তাকিয়েই একটি bool পেতে, গ্যারান্টি variableএবং api.call। আরও বেশি সি ++ অভিজ্ঞতার সাথে কেউ ব্যাখ্যা করতে পারে; সম্ভবত এটি একটি প্রতিরক্ষা-গভীরতার পরিমাপের ধরণের হিসাবে বোঝানো হয়েছে, গ্যারান্টি নয়।


সংকলক মানগুলির সাথে একইভাবে আচরণ করবে যদি এটি কেবল কোনও অপরেন্ড হিসাবে ব্যবহৃত হয় ifবা &&ব্যবহার করা হয় !!তবে এর if (!!(number & mask))পরিবর্তে কিছু সংকলক ব্যবহার করে সাহায্য করতে পারে bit triggered = !!(number & mask); if (triggered); বিট প্রকার সহ কিছু এম্বেড করা সংকলকগুলিতে, যেমন 256 বিট টাইপকে নির্ধারণ করা শূন্যের ফলন দেয়। এটি ছাড়া !!, আপাতদৃষ্টিতে-নিরাপদ রূপান্তর ( ifশর্তটি একটি ভেরিয়েবলের অনুলিপি করে এবং তারপরে ব্রাঞ্চিং) নিরাপদ হবে না।
সুপারক্যাট

0

সম্ভবত প্রোগ্রামাররা এরকম কিছু ভাবছিল ...

!! মাইআনসওয়ার বুলিয়ান। প্রসঙ্গে, এটি বুলিয়ান হওয়া উচিত, তবে আমি এটি নিশ্চিত করার জন্য কেবল ঠুং ঠুং শব্দ পছন্দ করি, কারণ একসময় আমার কাছে এক রহস্যময় বাগ ছিল যা আমাকে বিট করে, এবং ব্যাং ব্যাং করে, আমি এটি মেরে ফেলেছিলাম।


0

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

সি ++ তে ক্লাসগুলির জন্য বুলিয়ান পরীক্ষা প্রদানের বিভিন্ন উপায় রয়েছে।

একটি সুস্পষ্ট উপায় হ'ল operator boolরূপান্তর অপারেটর।

// operator bool version
  class Testable {
    bool ok_;
  public:
    explicit Testable(bool b=true):ok_(b) {}

    operator bool() const { // use bool conversion operator
      return ok_;
    }
  };

আমরা ক্লাস পরীক্ষা করতে পারি,

Testable test;
  if (test) 
    std::cout << "Yes, test is working!\n";
  else 
    std::cout << "No, test is not working!\n";

তবে opereator boolএটি অনিরাপদ হিসাবে বিবেচিত হয় কারণ এটি অযৌক্তিক ক্রিয়াকলাপগুলিকে যেমন test << 1;বা হিসাবে অনুমতি দেয় int i=test

ব্যবহার operator!করা নিরাপদ কারণ আমরা অন্তর্নিহিত রূপান্তর বা ওভারলোডিং সমস্যাগুলি এড়িয়ে চলেছি।

বাস্তবায়ন তুচ্ছ,

bool operator!() const { // use operator!
    return !ok_;
  }

পরীক্ষা দুই কথ্য উপায়ে Testableবস্তুর হয়

  Testable test;
  if (!!test) 
    std::cout << "Yes, test is working!\n";
  if (!test2) {
    std::cout << "No, test2 is not working!\n";

প্রথম সংস্করণটি if (!!test)কিছু লোককে ডাবল-ব্যাং ট্রিক বলে


1
সি ++ ১১, যেহেতু explicit operator boolঅন্য কোনও অবিচ্ছেদ্য ধরণের ক্ষেত্রে অন্তর্ভুক্ত রূপান্তর রোধ করতে ব্যবহার করতে পারেন ।
আরনে ভোগেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.