Подтвердить что ты не робот

Определение переменной в условии условия if-statement?

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

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. Поскольку было несколько замечаний по этому поводу, пожалуйста, проигнорируйте, что этот пример "плохой" или опасный. Я знаю что. Это первое, что пришло мне в голову, как пример.

4b9b3361

Ответ 1

Это разрешено спецификацией, поскольку С++ 98.

Из раздела 6.4 "Выражения выбора":

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

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

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

Ответ 2

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

enter image description here

Ответ 3

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

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

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

Ответ 4

Определение переменной в условной части операторов while, if и switch является стандартным. Соответствующим пунктом является пункт 6.4 [stmt.select], который определяет синтаксис условия.

Кстати, ваше использование бессмысленно: если new не удается, он генерирует исключение std::bad_alloc.

Ответ 5

Вот пример, демонстрирующий нестандартное использование переменной, объявленной в условии 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 года... теперь вы можете подражать тому, что я объяснил, не может быть сделано...

Это работает для подвижных классов, таких как ifstream в С++ 11 и даже для не копируемых классов начиная с С++ 17 с разрешением копирования.

Отредактировано май 2019: использовать авто, чтобы облегчить многословие

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