Всю жизнь казалось (хотя вроде и не когда не пользовался) что в if можно создать переменную и использовать её в блоке if. Теперь появилось auto, и подобное стало удобным и удобочитаемым. Попробовал:
if (( auto a = someFunction()).someMethodInA() )
{
// do something with a
}
Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?
M>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать?
Можно и раньше, и сейчас.
M> Или я что-то просто накосячил?
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, Marty, Вы писали:
M>>
if (( auto a = someFunction()).someMethodInA() )
M>>{
M>> // do something with a
M>>}
M>>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?
Pzz>Ты ее пытаешься завести не в if'е, а внутри выражения (из-за двух открывающих скобок). Этого тебе никто не обещал.
Без скобок тоже не компилится, их вообще добавил, так как непонятно, как правильно сразу вызвать метод этого объекта a, чтобы его результат уже проверялся if'ом.
#include <iostream>
using namespace std;
struct A
{
bool bValid;
bool isValid() { return bValid; }
A(bool b = false) : bValid(b) {}
};
A foo()
{
return true;
}
int main() {
// your code goes here
//if (auto a = foo()) //!!!!!!!!! как тут вызвать A::isValid()?if ((auto a = foo()).isValid()) // а так не работает
{
cout<<"a = "<<a<<"\n";
}
return 0;
}
Хотя, дошло. Нужно было лишь немного подумать, и получилось
Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?
Здравствуйте, Marty, Вы писали:
M>Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?
M> //if (auto a = foo()) //!!!!!!!!! как тут вызвать A::isValid()?
M> if ((auto a = foo()).isValid()) // а так не работает
в современном с++ можно так:
if (auto a=foo(); a.isValid()) ...
M>Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?
Смотри на "safe bool idiom".
Но сегодня это лишнее, так как теперь можно (и нужно) использовать explicit operator bool()
Здравствуйте, Constructor, Вы писали:
M>>Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?
C>Имеется в виду, по-видимому, идиома safe bool.
Посмотрел, там по ссылке о safe_bool есть и про explicit operator bool. Насколько я помню, explicit в cxx03 стандарте был только для конструкторов, и означал, что надо конструктор явно вызывать, или явно кастить объект через *_cast. В новом стандарте (cxx11), как я понимаю, если оператор bool — explicit operator bool — то в он будет применяться в тех выражениях/конструкциях/операциях, где явно нужен именно bool, и при использовании в операторе if (а там требуется bool результат) с одной стороны не нужно что-то явно кастить, с другой — гарантированно вызовется именно этот оператор. Я правильно понимаю?
).
Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).
Здравствуйте, watchmaker, Вы писали:
M>>А можно поподробнее, о чем ты?
W>В смысле теперь внутри if разрешено писать init-statement (в соседней ветке как раз уже пример написал
). W>Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).
Ага, ясно. Я пока в рамках c++11 интересуюсь. Во-первых — надо с чего-то начинать после c++03, во-вторых — кроме c++11 пока ничего нет и не предвидится
Здравствуйте, Marty, Вы писали:
M>Без скобок тоже не компилится, их вообще добавил, так как непонятно, как правильно сразу вызвать метод этого объекта a, чтобы его результат уже проверялся if'ом.
Запятая же.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, watchmaker, Вы писали:
W>Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).
Как так не было? Оператор запятая имеет приоритет ниже присваивания, и отлично работает для таких целей давным-давно.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Marty, Вы писали:
M>Насколько я помню, explicit в cxx03 стандарте был только для конструкторов, и означал, что надо конструктор явно вызывать, или явно кастить объект через *_cast.
Почему *_cast? Только C-style cast и static_cast.
M>В новом стандарте (cxx11), как я понимаю, если оператор bool — explicit operator bool — то в он будет применяться в тех выражениях/конструкциях/операциях, где явно нужен именно bool, и при использовании в операторе if (а там требуется bool результат) с одной стороны не нужно что-то явно кастить, с другой — гарантированно вызовется именно этот оператор. Я правильно понимаю?
В общем, да. explicit operator SomeType предотвращают возможность выполнения непредусмотренных операций, которые допускаются при использовании неявных user-defined conversion operators (вроде сравнения на равенство экземпляров двух разных классов, для которых определен user-defined conversion operator к одному и тому же третьему типу).
Здравствуйте, Ops, Вы писали:
W>>в современном с++ можно так: W>>
W>>if (auto a=foo(); a.isValid()) ...
W>>
Ops>Серьезно? А что это будет?
Это уже есть. В C++17 добавили if statement with initializer и switch statement with initializer (синтаксис в обоих случаях напоминает обычный цикл for). Подобный синтаксис для инициализации также планируется добавить для range-based for loop (в C++20).
Здравствуйте, Constructor, Вы писали:
C>Это уже есть. В C++17 добавили if statement with initializer и switch statement with initializer (синтаксис в обоих случаях напоминает обычный цикл for). Подобный синтаксис для инициализации также планируется добавить для range-based for loop (в C++20).
Я уже понял, название рядом таки написали. А в чем преимущество, по сравнению с использованием запятой?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
C>>Это уже есть. В C++17 добавили if statement with initializer и switch statement with initializer (синтаксис в обоих случаях напоминает обычный цикл for). Подобный синтаксис для инициализации также планируется добавить для range-based for loop (в C++20).
Ops>Я уже понял, название рядом таки написали. А в чем преимущество, по сравнению с использованием запятой?
Преимущество небольшое: if statement with initializer реально работает, а operator, в аналогичных условиях — нет.
Здравствуйте, Ops, Вы писали:
Ops>Здравствуйте, watchmaker, Вы писали:
W>>Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие
Ops>Как так не было? Оператор запятая имеет приоритет ниже присваивания, и отлично работает для таких целей давным-давно.
А продемонстрируй тогда, пожалуйста, как будет выглядеть процитированный фрагмент кода, но с оператором запятой в if
Ведь такое не скомпилируется:
struct A {
bool someMethodInA();
};
extern A someFunction();
extern void use (A);
void foo() {
if (auto a = someFunction(), a.someMethodInA()) { use(a); }
}
Re: Продолжение: Создать переменную со скопом для if
if (auto a = getSomething())
{
// true ветка
}
else
{
// false ветка
}
Как обычно, захотелось странного — выполнить только false ветку. Тупой код выглядит так:
if (auto a = getSomething()) {}
else
{
// false ветка
}
Идей, как красиво это сделать, нет вообще. Во первых, непонятно, как это записать, во вторых (что частично следует из первого) — какие операторы и как надо переопределить.
Немного подумав, решил добавить признак singleTimeInvert и operator!, и получилось хоть кривенько, но в принципе, то, что нужно. Но синтаксис тот еще, конечно:
if (auto a = !getSomething())
{
// false ветка
}
Вроде работает, но: Кривенько
Непонятно, насколько оптимально это соптимизируется
По идее, operator! будет вызван только раз, но мало ли, что-то может пойти не так
Может еще какие грабли есть
Еще есть мысль сделать operator!=, чтобы писать:
if (auto a != getSomething())
{
// false ветка
}
Но концепт не компилится
После этого до меня дошло, что != это не тоже самое, что и операторы вида -= (да и этот не сработает), но надеюсь, направление мысли понятно.