'যদি' এক্সপ্রেশনতে সি ++, ভেরিয়েবল ঘোষণা


113

এখানে কি হচ্ছে?

if(int a = Func1())
{
    // Works.
}

if((int a = Func1()))
{
    // Fails to compile.
}

if((int a = Func1())
    && (int b = Func2()))
)
{
    // Do stuff with a and b.
    // This is what I'd really like to be able to do.
}

2003 স্ট্যান্ডার্ডের 6.4.3 বিভাগে সিলেকশন স্টেটমেন্ট শর্তে ঘোষিত ভেরিয়েবলের কীভাবে শর্ত দ্বারা নিয়ন্ত্রিত সাবস্টেটমেন্টগুলির শেষ অবধি প্রসারিত হবে তা প্রসারণ করা হয়। তবে আমি ঘোষণার আশেপাশে প্রথম বন্ধনীর মুখোমুখি না হতে পারার বিষয়ে যেখানে কিছু বলেছে তা আমি দেখতে পাই না বা শর্ত অনুযায়ী কেবলমাত্র একটি ঘোষণা সম্পর্কে কিছুই বলে না।

এই সীমাবদ্ধতা এমনকি এমন পরিস্থিতিতে বিরক্তিকর হয় যেখানে শর্তে কেবলমাত্র একটি ঘোষণার প্রয়োজন হয়। এই বিবেচনা.

bool a = false, b = true;

if(bool x = a || b)
{

}

যদি আমি 'যদি' -র সাথে স্কোপটি x সেট করে লিখতে চাই তবে ডিক্লোরেশনের ক্ষেত্রে প্রথম বন্ধনী প্রয়োজন (যেহেতু অ্যাসাইনমেন্ট অপারেটরটি লজিক্যাল ওআরের চেয়ে কম অগ্রাধিকার পেয়েছে), তবে যেহেতু প্রথম বন্ধনী ব্যবহার করা যায় না এটি এক্স এর বাইরে ঘোষণার প্রয়োজন দেহ, প্রত্যাশার চেয়ে বৃহত্তর পরিসরে এই ঘোষণাকে ফাঁস করে দেয় স্পষ্টতই এই উদাহরণটি তুচ্ছ তবে আরও বাস্তবসম্মত ঘটনাটি হ'ল যেখানে a এবং b ফাংশন যেখানে মানগুলি প্রত্যাবর্তন করা দরকার

সুতরাং আমি কি স্ট্যান্ডার্ডের সাথে অ-সঙ্গতিপূর্ণ করতে চাই, বা আমার সংকলকটি কেবল আমার বলগুলিকে আবদ্ধ করছে (VS2008)?


6
"যদি আমি লুপটি প্রবেশ করতে চাই" <- আপনার উদাহরণগুলি রয়েছে ififএটি একটি লুপ নয়, এটি শর্তসাপেক্ষ।
ক্র্যাশস্ট্রিস্ট

2
@ ক্র্যাশ্মস্ট্র্ট: সত্য তবে এর শর্তগুলি while যেমন রয়েছে তেমন if
মাইক সিমুর

2
কমা অপারেটর দিয়ে এটি করা যায় না? আমি বলতে চাচ্ছি: if (int a = foo(), int b = bar(), a && b)? যদি কমা অপারেটরটি ওভারলোড না করা হয়, মানটি বলে যে এক্সপ্রেশনগুলি বাম থেকে ডানদিকে মূল্যায়ন করা হয় এবং ফলাফলটির মানটিই সর্বশেষ প্রকাশ। এটি forলুপ ইনিশিয়ালাইজেশন সহ কাজ করে , কেন এখানে নয়?
আর্চি

@ আর্চি: আমি এটি চেষ্টা করেছি, আমি এটি কাজে লাগাতে পারিনি। আপনি একটি কাজের উদাহরণ প্রদান করতে পারেন?
জেমস জনস্টন 15

@ জেমস জনস্টন: আমিও চেষ্টা করেছি, আর মনে হচ্ছে এটি কার্যকর হয় না। এই ধারণাটি সবেমাত্র আমার মাথার উপরের দিক থেকে এসেছিল, আমি কীভাবে ifকাজ করে তা থেকে প্রস্তাবিত হয়েছিল এবং এটি ভুল অনুমান বলে মনে হচ্ছে।
আরচি

উত্তর:


63

সি ++ 17 হিসাবে আপনি যা করার চেষ্টা করছেন তা শেষ পর্যন্ত সম্ভব :

if (int a = Func1(), b = Func2(); a && b)
{
    // Do stuff with a and b.
}

ঘোষণাপত্র এবং আসল শর্তটি পৃথক করার ;পরিবর্তে এর ব্যবহারটি নোট করুন ,


23
নিস! আমি সবসময় সন্দেহ করি যে আমি আমার সময়ের চেয়ে এগিয়ে ছিলাম।
নিউট্রিনো

106

আমি মনে করি আপনি ইতিমধ্যে ইস্যুতে ইঙ্গিত দিয়েছিলেন। সংকলকটি এই কোডটি দিয়ে কী করবে?

if (!((1 == 0) && (bool a = false))) {
    // what is "a" initialized to?

"&&" অপারেটর একটি শর্ট সার্কিট লজিক্যাল এবং। এর অর্থ হ'ল যদি প্রথম অংশটি (1==0)মিথ্যা বলে প্রমাণিত হয় তবে দ্বিতীয় অংশটি (bool a = false)মূল্যায়ন করা উচিত নয় কারণ এটি ইতিমধ্যে জানা গেছে যে চূড়ান্ত উত্তরটি মিথ্যা হবে। যদি (bool a = false)মূল্যায়ন না হয় তবে তার পরে কোডগুলি aকী ব্যবহার করবে ? আমরা কি ভেরিয়েবলটি আরম্ভ করে এটিকে অপরিবর্তিত রাখব না? আমরা কি এটি ডিফল্টরূপে সূচনা করব? যদি ডেটা টাইপটি কোনও শ্রেণি হত এবং এটি করার অনাকাঙ্ক্ষিত পার্শ্ব প্রতিক্রিয়া হয়? যদি আপনি পরিবর্তে boolকোনও ক্লাস ব্যবহার করেন এবং এর কোনও ডিফল্ট কনস্ট্রাক্টর নেই যা ব্যবহারকারীর অবশ্যই পরামিতি সরবরাহ করতে পারে - তবে আমরা কী করব?

এখানে আরও একটি উদাহরণ:

class Test {
public:
    // note that no default constructor is provided and user MUST
    // provide some value for parameter "p"
    Test(int p);
}

if (!((1 == 0) && (Test a = Test(5)))) {
    // now what do we do?!  what is "a" set to?

আপনি যে সীমাবদ্ধতা খুঁজে পেয়েছেন তা পুরোপুরি যুক্তিযুক্ত বলে মনে হচ্ছে - এটি এই ধরণের অস্পষ্টতা ঘটতে বাধা দেয়।


1
ভাল যুক্তি. ওপি বা অন্যরা এর সাথে পরিচিত না হলে আপনি স্পষ্টভাবে সংক্ষিপ্ত-সার্কিটের উল্লেখ করতে চাইতে পারেন।
ক্রিস কুপার

7
আমি এটা ভাবিনি। যদিও আপনি উদাহরণটিতে সংক্ষিপ্ত সঞ্চালন সরবরাহ করেছেন শর্তাধীন বিবৃতি সুযোগ প্রবেশ করা থেকে বাধা দেয়, সেক্ষেত্রে অভিব্যক্তির যে অংশটি ভেরিয়েবলটি প্রক্রিয়াজাতকরণ না করে বলে ঘোষণা করে তা কোনও সমস্যা নয়, কারণ এর পরিধি শর্তাধীন বিবৃতিতে সীমাবদ্ধ। কোন ক্ষেত্রে এটি আরও ভাল হবে না যদি সংকলক কেবল সেই ক্ষেত্রেই একটি ত্রুটি উত্থাপন করে যেখানে শর্তাধীন বিবৃতি সুযোগের কোনও সম্ভাব্যতা রয়েছে যখন ভেরিয়েবল ঘোষণার যে অংশটির প্রক্রিয়া করা হয়নি? আমি যে উদাহরণ দিয়েছি তা তেমন হয়নি।
নিউট্রিনো

@ নিউট্রিনো প্রথম দর্শনে আপনি ধারণাটি কিছুটা স্যাট-সমস্যার মতো মনে করছেন, যা কমপক্ষে সাধারণ ক্ষেত্রে সমাধান করা খুব সহজ নয়।
খ্রিস্টান রাউ

5
যদি আপনি এক্ষেত্রে একাধিক পরিবর্তনশীল ঘোষণাপত্রের সাথে সমস্ত সমস্যার বিষয়ে যা ব্যাখ্যা করেন এবং আপনি কেবলমাত্র সেগুলি একটি সীমিত উপায়ে ব্যবহার করতে পারেন তা আমাকে বিস্মিত করে তোলে কেন পৃথিবীতে এই ধরণের ঘোষণা প্রথম স্থানে চালু হয়েছিল। আমি কোনও কোড উদাহরণে দেখার আগে কখনও কখনও এ জাতীয় সিনট্যাক্সের প্রয়োজন অনুভব করিনি । আমি এই বাক্য গঠনটি বরং আনাড়ি মনে করি এবং আমি মনে করি যে যদি ব্লকের আগে ভেরিয়েবল ঘোষণা করা অনেক বেশি পঠনযোগ্য হয়। আপনার যদি সত্যিই সেই পরিবর্তনশীলটির সুযোগ সীমাবদ্ধ করতে হয় তবে আপনি যদি ব্লকের চারপাশে একটি অতিরিক্ত ব্লক রাখতে পারেন। আমি এই সিনট্যাক্সটি কখনও ব্যবহার করি নি।
জর্জিও 15

2
ব্যক্তিগতভাবে আমি মনে করি যে অতিরিক্ত নেস্টেড স্কোপিং ব্রেসগুলির মতো কুৎসিত ব্যবস্থা গ্রহণ না করে আপনি যে স্টেটমেন্ট ব্লকটি ব্যবহার করতে পারবেন সেগুলি যথাযথভাবে ব্যবহার করতে হবে এমন ভেরিয়েবলগুলির পরিসর সীমাবদ্ধ করতে সক্ষম হওয়া বরং এটি মার্জিত হবে।
নিউট্রিনো

96

একটি ইন শর্ত ifবা whileবিবৃতি পারেন একটি হতে পারে অভিব্যক্তি , অথবা একটি একক পরিবর্তনশীল ঘোষণা (initialisation সহ)।

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

আমি ঘোষণার আশেপাশে প্রথম বন্ধনীর মুখোমুখি না হতে পারার বিষয়ে যেখানে কিছু বলেছি তা দেখতে পাচ্ছি না, বা এটি শর্ত অনুযায়ী কেবলমাত্র একটি ঘোষণার বিষয়ে কিছুই বলে না।

6.4 / 1 এ সিনট্যাক্সের স্পেসিফিকেশন শর্তটির জন্য নিম্নলিখিতটি দেয়:

condition:
    expression
    type-specifier-seq declarator = assignment-expression

কোনও একক ঘোষনা নির্দিষ্ট করে, কোনও বন্ধনী বা অন্যান্য অলংকরণ ছাড়াই।


3
এর কোনও কারণ বা পটভূমি আছে কি?
টোমা জ্যাটো - মনিকা

23

আপনি যদি সংকীর্ণ সুযোগে ভেরিয়েবলগুলি আবদ্ধ করতে চান তবে আপনি সর্বদা অতিরিক্ত ব্যবহার করতে পারেন { }

//just use { and }
{
    bool a = false, b = true;

    if(bool x = a || b)
    {
        //...
    }
}//a and b are out of scope

5
+1 টি। অতিরিক্ত হিসাবে, আমি এক্স এর ঘোষণাকে আশেপাশের ব্লকে স্থানান্তরিত করব: কেন এটির একটি বিশেষ স্ট্যাটাস দেওয়া উচিত অ এবং বি?
জর্জিও

1
স্পষ্টতই, তবে বিশ্বাসযোগ্য নয়: সাধারণ লুপ ভেরিয়েবলের ক্ষেত্রেও এটি বলা যেতে পারে। (মঞ্জুর, সীমিত পরিবর্তনশীল সুযোগ প্রয়োজনীয়তার আরো অনেক কিছু লুপ খুবই সাধারণ বিষয়।)
পিটার - পুনর্বহাল মনিকা

18

শেষ বিভাগটি ইতিমধ্যে কাজ করে, আপনাকে কেবল এটি কিছুটা আলাদা লিখতে হবে:

if (int a = Func1())
{
   if (int b = Func2())
   {
        // do stuff with a and b
   }
}

2

এখানে একটি লুপ ব্যবহার করে একটি কুরুচিপূর্ণ কাজ রয়েছে (যদি উভয় ভেরিয়েবলগুলি পূর্ণসংখ্যা হয়):

#include <iostream>

int func1()
{
    return 4;
}

int func2()
{
    return 23;
}

int main()
{
    for (int a = func1(), b = func2(), i = 0;
        i == 0 && a && b; i++)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }

    return 0;
}

তবে এটি অন্যান্য প্রোগ্রামারদের বিভ্রান্ত করবে এবং এটি বরং খারাপ কোড, সুতরাং প্রস্তাবিত নয়।

একটি সাধারণ এনক্লোজিং {}ব্লক (ইতিমধ্যে প্রস্তাবিত হিসাবে) পড়া অনেক সহজ:

{
    int a = func1();
    int b = func2();

    if (a && b)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }
}

1

একটি বিষয় লক্ষণীয়, এটি হ'ল বৃহত্তর if-block এর ভিতরে থাকা ভাবগুলি

if (!((1 == 0) && (bool a = false)))

বাম-থেকে-ডান ফ্যাশনে মূল্যায়ন করার অগত্যা গ্যারান্টিযুক্ত নয়। একটি বরং সূক্ষ্ম বাগ যা আমি আবার ফিরে এসেছিলাম যে সংকলকটি আসলে বাম থেকে ডানে পরিবর্তে ডান থেকে বামে পরীক্ষা করছিল with


5
আজকাল, যাইহোক, সি 99 আদেশ দেয় যে && ও || বাম থেকে ডান মূল্যায়ন করা হয়।
b0fh

2
আমি মনে করি শর্ট সার্কিট যুক্তির কারণে যুক্তিগুলির ডান থেকে বামে মূল্যায়ন কখনই সম্ভব ছিল না। এটি সর্বদা একক অভিব্যক্তিতে পয়েন্টার এবং পয়েন্টটির পরীক্ষার মতো জিনিসের জন্য ব্যবহৃত হত if(p && p->str && *p->str) ...। ডান থেকে বাম মারাত্মক হত এবং সূক্ষ্ম না। অন্যান্য অপারেটরদের সাথে - এমনকি নিয়োগও! - এবং ফাংশন কল আর্গুমেন্ট আপনি সঠিক, কিন্তু শর্ট সার্কিট অপারেটরদের সাথে নয়।
পিটার - মনিকা পুনরায়

1

সামান্য টেম্পলেট যাদুতে আপনি একাধিক ভেরিয়েবল ঘোষণা করতে না পারার সমস্যাটিকে ঘিরে ধরতে পারেন:

#include <stdio.h>

template <class LHS, class RHS>
struct And_t {
  LHS lhs;
  RHS rhs;

  operator bool () {
    bool b_lhs(lhs);
    bool b_rhs(rhs);
    return b_lhs && b_rhs;
  }
};
template <class LHS, class RHS> 
And_t<LHS, RHS> And(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; }

template <class LHS, class RHS>
struct Or_t {
LHS lhs;
RHS rhs;

  operator bool () {
    bool b_lhs(lhs);
    bool b_rhs(rhs);
    return b_lhs || b_rhs;
  }
};
template <class LHS, class RHS> 
Or_t<LHS, RHS> Or(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; }

int main() {
  if (auto i = And(1, Or(0, 3))) {
    printf("%d %d %d\n", i.lhs, i.rhs.lhs, i.rhs.rhs);
  }
  return 0;
}

(দ্রষ্টব্য, এটি শর্ট সার্কিট মূল্যায়ন হারাবে))


আমি মনে করি এটি হারাবে (বা আলগা?)
পিটার - পুনরায় ইনস্টল করুন মনিকা

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