Comments 39
UFO just landed and posted this here
Тот самый случай, когда лучше пару лишних IF. И овцы останутся целы.
+8
В статье приведен тот случай, когда условие нужно выкинуть :)
Будет ли оно компилироваться, если вместо true/false подставить булевую переменную? Под всеми платформами и компиляторами скомпилируется?
Будет ли оно компилироваться, если вместо true/false подставить булевую переменную? Под всеми платформами и компиляторами скомпилируется?
0
UFO just landed and posted this here
Вроде такого:
не printf, но смысл тот же. Кажется, тернарный оператор для printf приводится как первый пример его использования в книге «Язык С» за авторством K & R. Там как раз множественные числа в тексте так обходились.
gtk_list_store_set(GTK_LIST_STORE(model), &iter, VM_TYPE, strcmp((char *)type, "1") ? "ВМ" : "Шаблон", -1);
не printf, но смысл тот же. Кажется, тернарный оператор для printf приводится как первый пример его использования в книге «Язык С» за авторством K & R. Там как раз множественные числа в тексте так обходились.
+2
В Си нет ссылок, поэтому общий тип, конечно, 'int', а не 'int&', и не работает. Но всё можно «исправить»:
*(condition ? &i : &j) = 45;
Не так красиво, но работает.+7
Вот это хорошо!
А то я тоже завис на таком извращении.
А то я тоже завис на таком извращении.
+1
UFO just landed and posted this here
А за такое в продакшене ТехДиректор по репе не настучит?
0
Этот топик не о продакшене, а о возможностях тернарного оператора. Я просто привёл «фикс» для примера в топике для Си. Но в принципе, иногда надо бывает выполнить что-то подобное, обычно делается так.
C++:
C/C++:
C++:
int& x = (condition ? i : j);
// some code
x = 45;
C/C++:
int* x = (condition ? &i : &j);
// some code
*x = 45;
0
Да, спорная запись. Заставлять компилятор размещать переменные в памяти, только ради того, чтобы не писать лишний if. И вдобавок, возможно, разрушить оптимизацию (изменив значение неизвестно какой переменной).
Хотя если подобное выражение находится в третьем выражении оператора for (что-нибудь вроде for(a=0,b=n;b-a>1;*(cond? &a: &b)=c){… } для бинарного поиска) — то туда if не вставить.
Хотя если подобное выражение находится в третьем выражении оператора for (что-нибудь вроде for(a=0,b=n;b-a>1;*(cond? &a: &b)=c){… } для бинарного поиска) — то туда if не вставить.
0
В данном случае это const char*. Но объект String(«dcba») уничтожится в конце выражения и s будет указывать на невалидную память.
Там проблема не с тернарным оператором а с классом строки.
const char *s = String("Abcd");
будет падать ничуть не хуже.
+15
Спасибо за статью. То что тернарный оператор может работать как lvalue знал, а то что это поведение определяется общим типом — нет.
Я бы еще упомянул про опасности связанные с низким приоритетом тернарного оператора, которые с успехом были раскрыты в одном из постов PVS Studio. Ну и про то, что части оператора являются точками следования, тоже стоило сказать.
Я бы еще упомянул про опасности связанные с низким приоритетом тернарного оператора, которые с успехом были раскрыты в одном из постов PVS Studio. Ну и про то, что части оператора являются точками следования, тоже стоило сказать.
+5
По поводу четвертого пункта, но почему не «return !true;»? :-)
P.S. Интересно, почему я не могу пользоваться тегом?
P.S. Интересно, почему я не могу пользоваться тегом?
-3
Часто пользуетесь в своем коде подобным?
Знать это хорошо, но знание ради знания это онанизм.
Знать это хорошо, но знание ради знания это онанизм.
-7
Вы не рассказали о самой интересной и малоизвестной фиче тернарного оператора — возможности использовать throw в нем.
+9
Приведите, пожалуйста, пример того, где это может быть оправдано.
0
int foo() {
return valid ? some_state : throw std::logic_error();
}
«Оправданность» в данном случае — понятие субъективное. Да, этот код можно написать с if. И он, наверное, будет так понятнее.
+6
Понятно, спасибо. Но с моей точки зрения это нехорошая практика. Выражение должно быть однозначное. Изначальный смысл тернарного оператора — выбор значения (тогда как условной конструкции — выбор ветви выполнения). Здесь же смешались в кучу кони, люди. Да, это компактнее, но стоит ли экономить на одном условии? Ради чего?
По своей сути это ничуть не лучше, чем выражение из недавней статьи про JavaScript:
которое является способом записи условия:
По своей сути это ничуть не лучше, чем выражение из недавней статьи про JavaScript:
!~utils.indexOf(adjacency, id) && adjacency.push(id);
которое является способом записи условия:
if (utils.indexOf(adjacency, id) >= 0)
adjacency.push(id);
+2
В constexpr функциях, чтобы можно было ловить различные ошибки в переданных аргументах на этапе компиляции. Подробнее можно посмотреть тут: scrutator.me/post/2013/11/19/constant_expressions.aspx
0
Кстати, в C++14 можно будет использовать if в constexpr.
0
Ну и заодно, при разговоре об общих типах, не вредно упомянуть о том, что void является допустимым типом операндов. Т.е. можно писать так:
true ? (void)C() : (void)D();
+10
Багфикс:
class String
{
public:
const char* operator() (arguments-of-the-function-operator-must-go-here);
operator const char*() const; // оператор приведения типа
};
+1
class fake_logger
{
public:
template<class T>
void operator << (const T& any)
{}
};
#ifdef BUILD_ON_WINDOWS
#define LOGGER() (true) ? __noop : fake_logger()
#else
#define LOGGER() (true) ? void() : fake_logger()
#endif
да макросы плохо, но бывает пользуюсь такой особеностью
чтобы «выключать» логгер в релизе и использовать синтаксис аля для стримов
LOGGER() << «blahblahblah»;
+1
А это точно не будет генерировать код при отключенном логере?
0
Я так понимаю, это равносильно
if (false) fake_logger() << "blah-blah";
+1
Точно? Не вижу я там «if (false)» Т.е. fake_logger дёргаться и параметры для "<<" него будут готовиться и если там строки, то это тяжёлые операции, которые будут выполнятся даже при отключённом логере.
0
LOGGER() << "blahblahblah";
Раскроется в:
(true) ? void() : fake_logger() << "blahblahblah";
что благодаря крайне высокому приоритету тернарного оператора эквивалентно:
(true) ? void() : (fake_logger() << "blahblahblah");
Так как до правой части дело не дойдёт, то и вычислений никаких там произведено не будет.
+2
Чем это лучше, чем
define LOGGER() fake_logger()
?+1
Спасибо за статью! Узнал много нового.
+1
Sign up to leave a comment.
Секреты тернарного оператора