80

これが許可されていることに、私はただショックを受けました:

if( int* x = new int( 20 ) )
{
    std::cout << *x << "!\n";
    // delete x;
}
else
{
    std::cout << *x << "!!!\n";
    // delete x;
}
// std:cout << *x; // error - x is not defined in this scope

それで、これは標準で許可されていますか、それとも単なるコンパイラ拡張機能ですか?


PS これについてはいくつかのコメントがありましたが、この例が「悪い」または危険であることは無視してください。いい考えがある。これは、例として、私の頭に浮かんだ最初のことです。

4

5 に答える 5

84

これは、C++98 以降の仕様で許可されています。

セクション6.4「選択ステートメント」から:

条件の宣言によって導入された名前 (type-specifier-seq または条件の宣言子によって導入された) は、その宣言のポイントから条件によって制御されるサブステートメントの終わりまでの範囲内にあります。

次の例は、同じセクションからのものです。

if (int x = f()) {
    int x;    // ill-formed, redeclaration of x
}
else {
    int x;    // ill-formed, redeclaration of x
}
于 2012-09-29T18:28:45.753 に答える
20

実際には答えではありませんが(ただし、コメントはコードサンプルにはあま​​り適していません)、それが非常に便利である理由は次のとおりです。

if (int* x = f()) {
    std::cout << *x << "\n";
}

APIが「オプション」タイプ(ブール変換も使用可能)を返す場合は常に、このタイプの構造を利用して、値を使用するのが適切なコンテキスト内でのみ変数にアクセスできるようにすることができます。それは本当に強力なイディオムです。

于 2012-09-29T19:39:38.620 に答える
18

これは、言語の古い C++ 98 バージョンでも標準です。

ここに画像の説明を入力

于 2012-09-29T18:28:28.593 に答える
7

whileif、およびswitchステートメントの条件部分での変数の定義は標準です。関連する句は、条件の構文を定義する 6.4 [stmt.select] パラグラフ 1 です。

ところで、あなたの使用は無意味です:失敗すると例外newがスローされます。std::bad_alloc

于 2012-09-29T18:27:22.370 に答える
2

if条件で宣言された変数の非典型的な使用法を示す例を次に示します。

変数のタイプはint &、ブール値に変換可能で、thenおよびelseブランチで使用できます。

#include <string>
#include <map>
#include <vector>
using namespace std;

vector<string> names {"john", "john", "jack", "john", "jack"};
names.push_back("bill"); // without this push_back, my g++ generated exe fails :-(
map<string, int> ages;
int babies = 0;
for (const auto & name : names) {
    if (int & age = ages[name]) {
        cout << name << " is already " << age++ << " year-old" << endl;
    } else {
        cout << name << " was just born as baby #" << ++babies << endl;
        ++age;
    }
}

出力は

john was just born as baby #1
john is already 1 year-old
jack was just born as baby #2
john is already 2 year-old
jack is already 1 year-old
bill was just born as baby #3

残念ながら、条件内の変数は「=」宣言構文でのみ宣言できます。

これにより、明示的なコンストラクターを持つ型の他の有用なケースが除外されます。

たとえば、を使用した次の例std::ifstreamはコンパイルされません...

if (std::ifstream is ("c:/tmp/input1.txt")) { // won't compile!
    std::cout << "true: " << is.rdbuf();
} else {
    is.open("c:/tmp/input2.txt");
    std::cout << "false: " << is.rdbuf();
}

2019年1月に編集...説明したことをエミュレートできるようになりました...

これは、C++11 の ifstream のような移動可能なクラスに対して機能し、C++17 以降のコピー省略を伴うコピー不可能なクラスに対しても機能します。

2019 年 5 月編集: auto を使用して冗長性を軽減

{
    if (auto is = std::ifstream ("missing.txt")) { // ok now !
        std::cout << "true: " << is.rdbuf();
    } else {
        is.open("main.cpp");
        std::cout << "false: " << is.rdbuf();
    }
}
struct NoCpy {
    int i;
    int j;
    NoCpy(int ii = 0, int jj = 0) : i (ii), j (jj) {}
    NoCpy(NoCpy&) = delete;
    NoCpy(NoCpy&&) = delete;
    operator bool() const {return i == j;}
    friend std::ostream & operator << (std::ostream & os, const NoCpy & x) {
        return os << "(" << x.i << ", " << x.j << ")";
    }
};
{
    auto x = NoCpy(); // ok compiles
    // auto y = x; // does not compile
    if (auto nocpy = NoCpy (7, 8)) {
        std::cout << "true: " << nocpy << std::endl;
    } else {
        std::cout << "false: " << nocpy << std::endl;
    }
}
于 2013-04-17T02:30:27.643 に答える