C ++, 'if' एक्सप्रेशन में वेरिएबल डिक्लेरेशन


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 के साथ 'if' -बॉडी स्कोप दर्ज करना चाहता हूं, तो घोषणा में कोष्ठक की जरूरत है (क्योंकि असाइनमेंट ऑपरेटर की तार्किक या की तुलना में कम पूर्वता है), लेकिन चूंकि कोष्ठक का उपयोग नहीं किया जा सकता है, इसलिए इसे x की घोषणा की आवश्यकता है शरीर, उस घोषणा को अधिक से अधिक दायरे में लीक करना वांछित है। जाहिर है कि यह उदाहरण तुच्छ है, लेकिन एक अधिक यथार्थवादी मामला एक होगा जहां ए और बी फ़ंक्शन मान लौट रहे हैं जिन्हें परीक्षण करने की आवश्यकता है

तो क्या मैं मानक के अनुसार गैर-अनुरूपता करना चाहता हूं, या क्या मेरा संकलक मेरी गेंदों (VS2008) को तोड़ रहा है?


6
"अगर मैं लूप में प्रवेश करना चाहता हूं" <- आपके उदाहरण हैं ififलूप नहीं है, यह एक सशर्त है।
क्रैश

2
@ क्रशमस्ट्र: सच है, लेकिन इसके लिए स्थितियां while समान हैं if
माइक सेमोर

2
क्या यह अल्पविराम ऑपरेटर के साथ नहीं किया जा सकता है? मेरा मतलब है if (int a = foo(), int b = bar(), a && b):? यदि अल्पविराम ऑपरेटर ओवरलोडेड नहीं है, तो मानक कहता है कि अभिव्यक्तियों का मूल्यांकन बाएं से दाएं किया जाता है, और परिणाम मान अंतिम अभिव्यक्ति है। यह forलूप्स इनिशियलाइज़ेशन के साथ काम करता है, यहाँ क्यों नहीं?
आर्ची

@ अर्ची: मैंने अभी-अभी यह कोशिश की, मैं इसे काम नहीं कर पाई। शायद आप एक काम करने का उदाहरण प्रदान कर सकते हैं?
जेम्स जॉनसन

@JamesJohnston: मैंने अभी भी कोशिश की है, और यह काम नहीं करता है। यह विचार सिर्फ मेरे सिर के ऊपर से आया था, मुझे सुझाव दिया गया था कि कैसे ifकाम करता है, और यह गलत धारणा है।
आर्ची

जवाबों:


63

C ++ 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
यदि आप सभी समस्याओं के बारे में समझाते हैं तो कई वेरिएबल घोषणाओं के साथ अगर कोई शर्त और तथ्य यह है कि आप उन्हें केवल एक प्रतिबंधित तरीके से उपयोग कर सकते हैं, तो मुझे आश्चर्य होता है कि पृथ्वी पर इस तरह की घोषणा पहले स्थान पर क्यों शुरू की गई थी। इससे पहले कि मैंने कुछ कोड उदाहरण में देखा, मुझे इस तरह के सिंटैक्स की आवश्यकता कभी महसूस नहीं हुई थी । मैं इस वाक्यविन्यास को अनाड़ी पाता हूं और मुझे लगता है कि अगर ब्लॉक को अधिक पठनीय घोषित किया जाए तो इससे पहले चर की घोषणा करना। यदि आपको वास्तव में उस चर के दायरे को प्रतिबंधित करने की आवश्यकता है, तो आप अगर ब्लॉक के चारों ओर एक अतिरिक्त ब्लॉक लगा सकते हैं। मैंने इस सिंटेक्स का कभी उपयोग नहीं किया है।
जियोर्जियो

2
व्यक्तिगत रूप से मुझे लगता है कि यह अतिरिक्त रूप से सुरुचिपूर्ण स्कोप ब्रेसिज़ जैसे बदसूरत उपायों का सहारा लेने के बिना, आप का उपयोग करने की आवश्यकता वाले बयान ब्लॉक के दायरे का उपयोग करने में सक्षम चर के दायरे को सीमित करने में सक्षम होने के लिए सुरुचिपूर्ण होगा।
न्यूट्रिनो

96

एक ifया whileबयान में स्थिति या तो एक अभिव्यक्ति हो सकती है , या एक एकल चर घोषणा (प्रारंभिक के साथ) हो सकती है।

आपके दूसरे और तीसरे उदाहरण न तो वैध अभिव्यक्ति हैं, न ही वैध घोषणाएं, क्योंकि एक घोषणा एक अभिव्यक्ति का हिस्सा नहीं बन सकती है। हालांकि यह आपके तीसरे उदाहरण की तरह कोड लिखने में सक्षम होने के लिए उपयोगी होगा, इसके लिए भाषा सिंटैक्स में एक महत्वपूर्ण बदलाव की आवश्यकता होगी।

मैं यह नहीं देखता कि घोषणा के आस-पास कोष्ठक लगाने में सक्षम नहीं होने के बारे में यह कुछ भी कहता है, और न ही इस शर्त के बारे में केवल एक घोषणा के बारे में कुछ भी कहता है।

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। इसके अतिरिक्त, मैं x की घोषणा को आसपास के ब्लॉक में ले जाऊंगा: इसके लिए विशेष स्टेटस a और b क्यों होना चाहिए?
जियोर्जियो

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 (!((1 == 0) && (bool a = false)))

जरूरी नहीं कि बाएं-से-दाएं फैशन का मूल्यांकन किया जाए। एक सूक्ष्म सूक्ष्म बग जो मुझे दिन में वापस आया था, इस तथ्य के साथ करना था कि संकलक वास्तव में बाएं से दाएं के बजाय दाएं-बाएं परीक्षण कर रहा था।


5
आजकल, हालांकि, C99 अनिवार्य है कि && और || बाएं से दाएं का मूल्यांकन किया जाता है।
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
मुझे लगता है कि ओपी का इरादा कोड संक्षिप्तता, स्पष्टता और स्थिरता था। आप प्रस्तावित "समाधान" विपरीत करता है।
द्युजनन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.