Определение переменной в части условия оператора if?


Я был просто шокирован, что это разрешено:

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

Итак, это разрешено стандартом или это просто расширение компилятора?


P. S. Как было несколько замечаний по этому поводу - пожалуйста игнорировать что этот пример является "плохим" или опасным. Я знаю, что. Это только первое, что пришло мне в голову, в качестве примера.

5 68

5 ответов:

это разрешено спецификацией, начиная с C++98.

из раздела 6.4 "операторы выбора":

имя, введенное объявлением в условии (либо введенное спецификатором типа-seq, либо декларатором условия), находится в области видимости от точки объявления до конца подстанций, управляемых условием.

следующий пример из того же раздела:

if (int x = f()) {
    int x;    // ill-formed, redeclaration of x
}
else {
    int x;    // ill-formed, redeclaration of x
}

это стандартно, даже в старой версии языка C++ 98:

enter image description here

Не совсем ответ (но комментарии не очень хорошо подходят для примеров кода), еще причина, почему это невероятно удобно:

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

всякий раз, когда API возвращает тип "option" (который также имеет доступное логическое преобразование), этот тип конструкции можно использовать так, чтобы переменная была доступна только в контексте, где целесообразно использовать ее значение. Это очень мощный язык.

определение переменной в условной части a while,if и switch заявление стандартные. Соответствующий пункт 6.4 [stmt.выбрать пункт 1, который определяет синтаксис для условия.

кстати, ваше использование бессмысленно: если new он не бросает!--4--> исключения.

вот пример, демонстрирующий нетипичное использование переменной, объявленной в если состояние.

тип переменной int & который одновременно преобразуется в логический и может использоваться в затем и другое филиалы.

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