Здравствуйте, 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, в аналогичных условиях — нет.
Здравствуйте, 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()
).
Это позволяет просто без заморочек объявить переменную и задать на неё условие:
if (auto a = someFunction(); a.someMethodInA()) { use(a); }
До C++17 не было возможности указать произвольное условие: если переменная объявлялась, то она сама была условием (ну т.е. всегда bool(a) для вышеприведённого кода).
Здравствуйте, Marty, Вы писали:
M>Без скобок тоже не компилится, их вообще добавил, так как непонятно, как правильно сразу вызвать метод этого объекта a, чтобы его результат уже проверялся if'ом.
Запятая же.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Всю жизнь казалось (хотя вроде и не когда не пользовался) что в 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, или совместно с ним). Не напомните, в чем там хитрость, если вообще есть?
Здравствуйте, 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 результат) с одной стороны не нужно что-то явно кастить, с другой — гарантированно вызовется именно этот оператор. Я правильно понимаю?
Здравствуйте, 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 пока ничего нет и не предвидится
Здравствуйте, 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, Вы писали:
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 ветка
}
Но концепт не компилится
После этого до меня дошло, что != это не тоже самое, что и операторы вида -= (да и этот не сработает), но надеюсь, направление мысли понятно.
Здравствуйте, Marty, Вы писали:
M>Как обычно, захотелось странного — выполнить только false ветку. Тупой код выглядит так: M>
if (auto a = getSomething()) {}
M>else
M>{
M> // false ветка
M>}
M>
M>Идей, как красиво это сделать, нет вообще. Во первых, непонятно, как это записать, во вторых (что частично следует из первого) — какие операторы и как надо переопределить.
А чем неустраивает обычная запись вида
{ auto a=getSomething(); if (condition(a)) {
// condition ветка
}}
Re[3]: Продолжение: Создать переменную со скопом для if
Здравствуйте, watchmaker, Вы писали:
M>>Идей, как красиво это сделать, нет вообще.
W>Оставить как есть, либо вынести объявление из условия. W>Ну, право, что ты хочешь выгадать от замены?
Вынести объявление из условия — не вариант, идея была в том, чтобы получить код ошибки в одном флаконе с возвращаемым значением, сразу проверить его на ошибку, сделать что-то полезное в true и false ветках, используя это значение, или, в случае ошибки — код ошибки, и при этом не захламлять именами временных переменных scope, в котором всё это делается.
В принципе, почти все цели удалось достичь, и достаточно элегантно, но вот только ветку false неудобно обрабатывать, если есть только она одна. А кейс довольно частый — проверить результат, и если ошибка, то вернуть её выше, ничего больше не делая
Здравствуйте, kov_serg, Вы писали:
M>>Идей, как красиво это сделать, нет вообще. Во первых, непонятно, как это записать, во вторых (что частично следует из первого) — какие операторы и как надо переопределить. _>А чем неустраивает обычная запись вида _>
_>{ auto a=getSomething(); if (condition(a)) {
_> // condition ветка
_>}}
_>
Относительным неудобством по сравнению с тем, что уже удалось реализовать. Лишние скобки, лишний отступ, лишняя ненужная писанина, которая визуально захламляет код.
Здравствуйте, Marty, Вы писали:
M> Здравствуйте!
M>Всю жизнь казалось (хотя вроде и не когда не пользовался) что в if можно создать переменную и использовать её в блоке if. Теперь появилось auto, и подобное стало удобным и удобочитаемым. Попробовал: M>
if (( auto a = someFunction()).someMethodInA() )
M>{
M> // do something with a
M>}
M>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?
Так низя. В С++17 можно так
if( auto a = someFunction() ; a.someMethodInA() )
{
// do something with a
}
Здравствуйте, Marty, Вы писали:
_>>А чем неустраивает обычная запись вида _>>
_>>{ auto a=getSomething(); if (condition(a)) {
_>> // condition ветка
_>>}}
_>>
M>Относительным неудобством по сравнению с тем, что уже удалось реализовать. Лишние скобки, лишний отступ, лишняя ненужная писанина, которая визуально захламляет код.
Всегда радовало такое оправдание Компилятору плевать на лишние скобки и лишний отступ. А вот сгородить хрень неводомую это всегда пожалйуста, и только ради того чтобы выглядело приятнее на наш взляд.
Здравствуйте, kov_serg, Вы писали:
M>>Относительным неудобством по сравнению с тем, что уже удалось реализовать. Лишние скобки, лишний отступ, лишняя ненужная писанина, которая визуально захламляет код. _>Всегда радовало такое оправдание Компилятору плевать на лишние скобки и лишний отступ. А вот сгородить хрень неводомую это всегда пожалйуста, и только ради того чтобы выглядело приятнее на наш взляд.
Компилятору плевать, а мне нет. Код-то читает и поддерживает не компилятор
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, kov_serg, Вы писали:
M>>>Относительным неудобством по сравнению с тем, что уже удалось реализовать. Лишние скобки, лишний отступ, лишняя ненужная писанина, которая визуально захламляет код. _>>Всегда радовало такое оправдание Компилятору плевать на лишние скобки и лишний отступ. А вот сгородить хрень неводомую это всегда пожалйуста, и только ради того чтобы выглядело приятнее на наш взляд.
M>Компилятору плевать, а мне нет. Код-то читает и поддерживает не компилятор
Можно, конечно, сетовать, что отступ лишний присутствует. Но по крайней мере этот код любой программист прочитает и поймёт с первого взгляда. Это же и одно из самых главный свойств приятного для поддержки кода.
А твой код с точки зрения поддержки человеком как раз и ужасен. В нём ни черта не понятно что происходит без заглядывания во внутренности класса.
Да даже тупой макрос
#define IF_NOT(cond) if (cond) {} else
выглядит на порядок более поддерживаемым. Уж по крайней мере глядя на код
IF_NOT(auto a = getSomething()) {
use(a);
}
можно составить гипотезу что он делает.
Короче, реально, если хочешь сэкономить отступ, то лучше напиши макрос.
Re[7]: Продолжение: Создать переменную со скопом для if
Здравствуйте, watchmaker, Вы писали:
M>>>>Относительным неудобством по сравнению с тем, что уже удалось реализовать. Лишние скобки, лишний отступ, лишняя ненужная писанина, которая визуально захламляет код. _>>>Всегда радовало такое оправдание Компилятору плевать на лишние скобки и лишний отступ. А вот сгородить хрень неводомую это всегда пожалйуста, и только ради того чтобы выглядело приятнее на наш взляд.
M>>Компилятору плевать, а мне нет. Код-то читает и поддерживает не компилятор
W>Можно, конечно, сетовать, что отступ лишний присутствует. Но по крайней мере этот код любой программист прочитает и поймёт с первого взгляда. Это же и одно из самых главный свойств приятного для поддержки кода.
Любой программист нам не нужен
Ты на работу тоже наверно берешь только тех, кто знает в C++? Или любителей vbs сам натаскиваешь?
Решение чисто прикладное, всем в команде оно понравилось (я про первое решение, без поддержки false ветки как единственной)
W>А твой код с точки зрения поддержки человеком как раз и ужасен. В нём ни черта не понятно что происходит без заглядывания во внутренности класса.
Нужно будет просто разок прочитать coding conventionals и заглянуть во внутренности. Там 50 строчек кода. Не вижу проблемы.
W>Да даже тупой макрос
#define IF_NOT(cond) if (cond) {} else
выглядит на порядок более поддерживаемым. Уж по крайней мере глядя на код
IF_NOT(auto a = getSomething()) {
W> use(a);
W>}
можно составить гипотезу что он делает.
На кофейной гуще гадать тоже весьма продуктивно — качество предсказаний примерно такое же.
W>Короче, реально, если хочешь сэкономить отступ, то лучше напиши макрос.
Базовая идея у тебя отторжения не вызывает? Так? Или нет?
Если надо проверить результат на true, то пишем на C++, а если надо проверить результат на false, то пишем говнокод на макросах? Отличное решение, в духе C++20, не меньше. Или я чего-то не понимаю?
Здравствуйте, Marty, Вы писали:
M> Здравствуйте!
M>Всю жизнь казалось (хотя вроде и не когда не пользовался) что в if можно создать переменную и использовать её в блоке if. Теперь появилось auto, и подобное стало удобным и удобочитаемым. Попробовал: M>
if (( auto a = someFunction()).someMethodInA() )
M>{
M> // do something with a
M>}
M>Но что-то не компилится. Это у меня такой глюк был и на самом деле ни раньше, ни сейчас такое нельзя сделать? Или я что-то просто накосячил?
C++17:
if ( auto a = someFunction(); a.someMethodInA() )
{
// do something with a
}