Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 19:32
Оценка:
Здравствуйте!

Всю жизнь казалось (хотя вроде и не когда не пользовался) что в if можно создать переменную и использовать её в блоке if. Теперь появилось auto, и подобное стало удобным и удобочитаемым. Попробовал:
if (( auto a = someFunction()).someMethodInA() )
{
    // do something with a
}


Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?
Маньяк Робокряк колесит по городу
Re: Создать переменную со скопом для if
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.04.18 19:35
Оценка: 8 (1) +2
Здравствуйте, Marty, Вы писали:

M>
if (( auto a = someFunction()).someMethodInA() )
M>{
M>    // do something with a
M>}


M>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?


Ты ее пытаешься завести не в if'е, а внутри выражения (из-за двух открывающих скобок). Этого тебе никто не обещал.
Re: Создать переменную со скопом для if
От: watchmaker  
Дата: 10.04.18 19:43
Оценка:
Здравствуйте, Marty, Вы писали:



M>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать?

Можно и раньше, и сейчас.

M> Или я что-то просто накосячил?


Да, там другая запись:

http://en.cppreference.com/w/cpp/language/if


И с С++17 появилась еще альтернатива более удобная.
Re[2]: Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 19:55
Оценка:
Здравствуйте, 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;

int foo()
{
    return 1;    
}

int main() {
    // your code goes here
    if (int a = foo())
    {
        cout<<"a = "<<a<<"\n";
    }
    return 0;
}


А нужно примерно такое:
#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;
}
Маньяк Робокряк колесит по городу
Re[3]: Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 20:08
Оценка:
Здравствуйте, Marty, Вы писали:

Хотя, дошло. Нужно было лишь немного подумать, и получилось

Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?

Код:
#include <iostream>
using namespace std;


struct A
{
    bool bValid;
    int  value;
    bool isValid() { return bValid; }
    
    A(bool b = false) : bValid(b) {}
    A(int v) : bValid(true), value(v)  {} 
    
    operator bool() const
    {
        return bValid;
    }

};

A foo()
{
    return 5;    
}

A bar()
{
    return false;
}

int main() {

    if (auto a = foo())
    {
        cout<<"a = "<<a.value<<"\n";
    }
    else
    {
        cout<<"a is not valid\n";
    }

    if (auto b = bar())
    {
        cout<<"b = "<<b.value<<"\n";
    }
    else
    {
        cout<<"b is not valid\n";
    }
    
    return 0;
}


Надо еще на C++11 проверить, работает ли.
Маньяк Робокряк колесит по городу
Отредактировано 10.04.2018 20:29 Marty . Предыдущая версия .
Re[4]: Создать переменную со скопом для if
От: Constructor  
Дата: 10.04.18 21:06
Оценка: 13 (2)
Здравствуйте, Marty, Вы писали:

M>Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?


Имеется в виду, по-видимому, идиома safe bool. Начиная с C++11, вместо нее лучше использовать explicit operator bool.
Re[4]: Создать переменную со скопом для if
От: watchmaker  
Дата: 10.04.18 21:14
Оценка: 8 (1) +1
Здравствуйте, Marty, Вы писали:

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()
Отредактировано 10.04.2018 22:42 watchmaker . Предыдущая версия .
Re[5]: Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 22:12
Оценка:
Здравствуйте, Constructor, Вы писали:

M>>Остался вопрос — смутно помню, почему-то в подобных случаях рекомендовалось перегружать и operator void* (или вместо operator bool, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?


C>Имеется в виду, по-видимому, идиома safe bool.


Даже, что-то вроде. Хотя, было как-то проще


C>Начиная с C++11, вместо нее лучше использовать explicit operator bool.


Посмотрел, там по ссылке о safe_bool есть и про explicit operator bool. Насколько я помню, explicit в cxx03 стандарте был только для конструкторов, и означал, что надо конструктор явно вызывать, или явно кастить объект через *_cast. В новом стандарте (cxx11), как я понимаю, если оператор bool — explicit operator bool — то в он будет применяться в тех выражениях/конструкциях/операциях, где явно нужен именно bool, и при использовании в операторе if (а там требуется bool результат) с одной стороны не нужно что-то явно кастить, с другой — гарантированно вызовется именно этот оператор. Я правильно понимаю?
Маньяк Робокряк колесит по городу
Re[2]: Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 22:16
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>И с С++17 появилась еще альтернатива более удобная.


А можно поподробнее, о чем ты?
Маньяк Робокряк колесит по городу
Re[3]: Создать переменную со скопом для if
От: watchmaker  
Дата: 10.04.18 22:41
Оценка: 8 (1)
Здравствуйте, Marty, Вы писали:

M>А можно поподробнее, о чем ты?


В смысле теперь внутри if разрешено писать init-statement (в соседней ветке как раз уже пример написал
Автор: watchmaker
Дата: 11.04.18
).
Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).
Re[4]: Создать переменную со скопом для if
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.04.18 23:05
Оценка:
Здравствуйте, watchmaker, Вы писали:

M>>А можно поподробнее, о чем ты?


W>В смысле теперь внутри if разрешено писать init-statement (в соседней ветке как раз уже пример написал
Автор: watchmaker
Дата: 11.04.18
).

W>Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).


Ага, ясно. Я пока в рамках c++11 интересуюсь. Во-первых — надо с чего-то начинать после c++03, во-вторых — кроме c++11 пока ничего нет и не предвидится
Маньяк Робокряк колесит по городу
Re[3]: Создать переменную со скопом для if
От: Ops Россия  
Дата: 11.04.18 05:56
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Без скобок тоже не компилится, их вообще добавил, так как непонятно, как правильно сразу вызвать метод этого объекта a, чтобы его результат уже проверялся if'ом.


Запятая же.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[5]: Создать переменную со скопом для if
От: Ops Россия  
Дата: 11.04.18 06:00
Оценка: +1 -2
Здравствуйте, watchmaker, Вы писали:

W>в современном с++ можно так:

W>
W>if (auto a=foo(); a.isValid()) ...
W>


Серьезно? А что это будет? Или ты имел в виду

W>
W>if (auto a=foo(), a.isValid()) ...
W>
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[4]: Создать переменную со скопом для if
От: Ops Россия  
Дата: 11.04.18 06:44
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).


Как так не было? Оператор запятая имеет приоритет ниже присваивания, и отлично работает для таких целей давным-давно.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[6]: Создать переменную со скопом для if
От: Constructor  
Дата: 11.04.18 07:07
Оценка:
Здравствуйте, 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 к одному и тому же третьему типу).
Re[6]: Создать переменную со скопом для if
От: Constructor  
Дата: 11.04.18 07:18
Оценка:
Здравствуйте, 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).
Re[7]: Создать переменную со скопом для if
От: Ops Россия  
Дата: 11.04.18 07:20
Оценка:
Здравствуйте, Constructor, Вы писали:

C>Это уже есть. В C++17 добавили if statement with initializer и switch statement with initializer (синтаксис в обоих случаях напоминает обычный цикл for). Подобный синтаксис для инициализации также планируется добавить для range-based for loop (в C++20).


Я уже понял, название рядом таки написали. А в чем преимущество, по сравнению с использованием запятой?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[8]: Создать переменную со скопом для if
От: Constructor  
Дата: 11.04.18 07:31
Оценка: 8 (1) +1 :)
Здравствуйте, 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, в аналогичных условиях — нет.
Re[5]: Создать переменную со скопом для if
От: watchmaker  
Дата: 11.04.18 08:45
Оценка:
Здравствуйте, 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
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 11.04.18 17:19
Оценка:
Здравствуйте, Marty, Вы писали:

Вопрос решился примерно так
Автор: Marty
Дата: 10.04.18


Но возник новый вопрос. Сейчас это работает так:
if (auto a = getSomething())
{
    // true ветка
}
else
{
    // false ветка
}


Как обычно, захотелось странного — выполнить только false ветку. Тупой код выглядит так:
if (auto a = getSomething()) {}
else
{
    // false ветка
}


Идей, как красиво это сделать, нет вообще. Во первых, непонятно, как это записать, во вторых (что частично следует из первого) — какие операторы и как надо переопределить.


Немного подумав, решил добавить признак singleTimeInvert и operator!, и получилось хоть кривенько, но в принципе, то, что нужно. Но синтаксис тот еще, конечно:
if (auto a = !getSomething())
{
    // false ветка
}


Вроде работает, но:
  1. Кривенько
  2. Непонятно, насколько оптимально это соптимизируется
  3. По идее, operator! будет вызван только раз, но мало ли, что-то может пойти не так
  4. Может еще какие грабли есть

Еще есть мысль сделать operator!=, чтобы писать:
if (auto a != getSomething())
{
    // false ветка
}


Но концепт не компилится
После этого до меня дошло, что != это не тоже самое, что и операторы вида -= (да и этот не сработает), но надеюсь, направление мысли понятно.


Вообщем, коллеги, помогайте идеями
Маньяк Робокряк колесит по городу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.