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

Могу ли я написать этот оператор if с объявлением переменной в одной строке?

Мне было интересно, есть ли способ поставить это на одну строку?

if (auto r = getGlobalObjectByName(word)) r->doSomething; // This works fine

if (!auto r = getGlobalObjectByName(word)) r->doSomething; // Says "expected an expression"

if (auto r = getGlobalObjectByName(word) == false) r->doSomething; // Also doesn't work.

Я также пытался окружить его дополнительными скобками, но это, похоже, не работает. Я считаю, что это действительно удобно делать на одной линии.

4b9b3361

Ответ 1

С С++ 17 вы можете использовать инициализатор if-statement:

if (auto r = getGlobalObjectByName(word); !r) r->doSomething;

Семантика:

if (init-statement; condition) statement

Единственное отличие от "традиционного" оператора if - это init-statement, который инициализирует переменную в области блока, похожую на for-loops.

Ответ 2

Если у вас есть С++ 17, используйте форму if (init statement; condition). Если нет, у вас есть три варианта:

  • Остановите попытку сохранить все это на одной строке. Например:

    auto r = getGlobalObjectByName(word);
    if (!r) r->doSomething();
    
  • Используйте else:

    if (auto r = getGlobalObjectByName(word)) {} else r->doSomething();
    

(Обратите внимание, что это требует, чтобы r был умным указателем с очень странной семантикой для функции operator bool(). OTOH, я предполагаю, что это фактический короткий фрагмент кода примера, а не ваш фактический код).

Я думаю, что я бы использовал только форму else, если было действительно важно сохранить все на одной строке (чтобы сохранить табличное форматирование кода, например).

Ответ 3

То, что вы пытаетесь сделать, прекрасно. Определяя переменную внутри, если вы ограничиваете ее область действия. Это помогает уменьшить количество блуждающих переменных после того, как они выполнили свою задачу.

Используя этот метод, если вы хотите следовать отрицательному пути, вам нужно использовать else следующим образом:

if(auto r = getGlobalObjectByName(word))
{
    r->doSomething();
}
else
{
    // r == nullptr
    // so do something else
}

Ответ 4

Также есть способ сделать это с lambdas и С++ 14, но это выглядит довольно глупо.

[](auto r){ if(!r)r->doSomething(); }(getGlobalObjectByName(word));

В С++ 11 вы также можете сделать этот ужасный беспорядок (та же идея, просто нет auto)

[](decltype(getGlobalObjectByName(word)) r){ if(!r)r->doSomething(); }(getGlobalObjectByName(word));

Это, конечно, не лучше, чем эта более ясная версия С++ 11, упомянутая Мартин Боннер:

{
    auto r = getGlobalObjectByName(word);
    if(!r)r->doSomething();
}

Здесь в вашем коде ясно, что вы хотите, чтобы r находился только на протяжении всего оператора if.

Ответ 5

До С++ 17 вы можете определить класс-оболочку, например здесь:

#include <utility>
template<typename T>
class NotT
{
    T t;
public:
    template<typename U>
    NotT(U&& u) : t(std::move(u)) {}
    explicit operator bool() const { return !t; }
    T      & value()       { return t; }
    T const& value() const { return t; }
};
template<typename T> NotT<T> Not(T&& t)
{
    return NotT<T>(std::move(t));
}

#include <memory>
#include <iostream>

int main()
{
    if(auto p=Not(std::make_shared<int>(2134)))
        std::cout << "!p: p=" << p.value().get() << '\n';
    else
        std::cout << "!!p: p=" << p.value().get() << ", *p=" << *p.value() << '\n';

}

Live example