it-swarm-id.com

C++, deklarasi variabel dalam ekspresi 'jika'

Apa yang terjadi di sini?

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.
}

Bagian 6.4.3 dalam standar 2003 menjelaskan bagaimana variabel yang dideklarasikan dalam kondisi pernyataan seleksi memiliki ruang lingkup yang meluas hingga akhir substitusi yang dikendalikan oleh kondisi tersebut. Tapi saya tidak melihat di mana dikatakan apa-apa tentang tidak bisa menempatkan tanda kurung di sekitar deklarasi, juga tidak mengatakan apa-apa tentang hanya satu deklarasi per syarat.

Batasan ini mengganggu bahkan dalam kasus di mana hanya satu deklarasi dalam kondisi yang diperlukan. Pertimbangkan ini.

bool a = false, b = true;

if(bool x = a || b)
{

}

Jika saya ingin memasukkan 'jika "-ruang lingkup dengan x disetel ke false maka deklarasi perlu tanda kurung (karena operator penugasan memiliki prioritas lebih rendah daripada OR logis), tetapi karena tanda kurung tidak dapat digunakan memerlukan deklarasi x di luar tubuh, membocorkan deklarasi itu ke ruang lingkup yang lebih besar dari yang diinginkan Jelas contoh ini sepele tetapi kasus yang lebih realistis akan menjadi salah satu di mana a dan b adalah fungsi mengembalikan nilai yang perlu diuji 

Jadi apakah yang ingin saya lakukan tidak sesuai dengan standar, atau apakah kompiler saya hanya menghentak bola saya (VS2008)?

96
Neutrino

Kondisi dalam pernyataan if atau while dapat berupa ekspresi , atau variabel tunggal deklarasi (dengan inisialisasi).

Contoh kedua dan ketiga Anda bukan merupakan ekspresi yang valid, atau deklarasi yang valid, karena deklarasi tidak dapat membentuk bagian dari ekspresi. Meskipun akan berguna untuk dapat menulis kode seperti contoh ketiga Anda, itu akan memerlukan perubahan signifikan pada sintaksis bahasa.

Saya tidak melihat di mana dikatakan apa-apa tentang tidak bisa menempatkan tanda kurung di sekitar deklarasi, juga tidak mengatakan apa-apa tentang hanya satu deklarasi per syarat.

Spesifikasi sintaks pada 6.4/1 memberikan hal berikut untuk kondisi:

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

menentukan satu deklarasi, tanpa tanda kurung atau perhiasan lainnya.

88
Mike Seymour

Saya pikir Anda sudah mengisyaratkan masalah ini. Apa yang harus dilakukan oleh kompiler dengan kode ini?

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

Operator "&&" adalah logika hubungan singkat DAN. Itu berarti bahwa jika bagian pertama (1==0) ternyata salah, maka bagian kedua (bool a = false) tidak boleh dievaluasi karena sudah diketahui bahwa jawaban terakhir akan salah. Jika (bool a = false) tidak dievaluasi, lalu apa yang harus dilakukan dengan kode nanti yang menggunakan a? Apakah kita tidak menginisialisasi variabel dan membiarkannya tidak terdefinisi? Apakah kita akan menginisialisasi ke default? Bagaimana jika tipe data adalah kelas dan melakukan ini memiliki efek samping yang tidak diinginkan? Bagaimana jika alih-alih bool Anda menggunakan kelas dan tidak memiliki konstruktor default sehingga pengguna harus memberikan parameter - lalu apa yang kita lakukan?

Ini contoh lain:

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?

Sepertinya batasan yang Anda temukan kelihatannya sangat masuk akal - ini mencegah terjadinya ambiguitas semacam ini.

97
James Johnston

Pada C++ 17 apa yang Anda coba lakukan akhirnya mungkin :

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

Perhatikan penggunaan ; bukannya , untuk memisahkan deklarasi dan kondisi aktual.

32
fwyzard

Jika Anda ingin menyertakan variabel dalam cakupan yang lebih sempit, Anda selalu dapat menggunakan { } tambahan

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

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

Bagian terakhir sudah berfungsi, Anda hanya perlu menulisnya sedikit berbeda:

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

Berikut ini solusi buruk menggunakan loop (jika kedua variabel bilangan bulat):

#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;
}

Tapi ini akan membingungkan programmer lain dan itu kode yang agak buruk, jadi tidak disarankan.

Blok {} terlampir sederhana (seperti yang sudah disarankan) jauh lebih mudah dibaca:

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

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

Satu hal yang perlu diperhatikan, juga adalah ekspresi di dalam if-block yang lebih besar

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

tidak selalu dijamin untuk dievaluasi dengan cara dari kiri ke kanan. Satu bug yang agak halus yang saya miliki pada hari itu berkaitan dengan fakta bahwa kompiler benar-benar menguji dari kanan ke kiri, bukan dari kiri ke kanan.

1
DukeBrymin

Dengan sedikit templat sulap, Anda bisa mengatasi masalah tidak bisa mendeklarasikan beberapa variabel:

#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;
}

(Catatan, ini kehilangan evaluasi hubungan pendek.) 

0
BCS