Комментарии 39
НЛО прилетело и опубликовало эту надпись здесь
Тот самый случай, когда лучше пару лишних IF. И овцы останутся целы.
В статье приведен тот случай, когда условие нужно выкинуть :)
Будет ли оно компилироваться, если вместо true/false подставить булевую переменную? Под всеми платформами и компиляторами скомпилируется?
Будет ли оно компилироваться, если вместо true/false подставить булевую переменную? Под всеми платформами и компиляторами скомпилируется?
НЛО прилетело и опубликовало эту надпись здесь
Вроде такого:
не printf, но смысл тот же. Кажется, тернарный оператор для printf приводится как первый пример его использования в книге «Язык С» за авторством K & R. Там как раз множественные числа в тексте так обходились.
gtk_list_store_set(GTK_LIST_STORE(model), &iter, VM_TYPE, strcmp((char *)type, "1") ? "ВМ" : "Шаблон", -1);
не printf, но смысл тот же. Кажется, тернарный оператор для printf приводится как первый пример его использования в книге «Язык С» за авторством K & R. Там как раз множественные числа в тексте так обходились.
В Си нет ссылок, поэтому общий тип, конечно, 'int', а не 'int&', и не работает. Но всё можно «исправить»:
*(condition ? &i : &j) = 45;
Не так красиво, но работает.Вот это хорошо!
А то я тоже завис на таком извращении.
А то я тоже завис на таком извращении.
НЛО прилетело и опубликовало эту надпись здесь
А за такое в продакшене ТехДиректор по репе не настучит?
Этот топик не о продакшене, а о возможностях тернарного оператора. Я просто привёл «фикс» для примера в топике для Си. Но в принципе, иногда надо бывает выполнить что-то подобное, обычно делается так.
C++:
C/C++:
C++:
int& x = (condition ? i : j);
// some code
x = 45;
C/C++:
int* x = (condition ? &i : &j);
// some code
*x = 45;
Да, спорная запись. Заставлять компилятор размещать переменные в памяти, только ради того, чтобы не писать лишний 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 не вставить.
В данном случае это const char*. Но объект String(«dcba») уничтожится в конце выражения и s будет указывать на невалидную память.
Там проблема не с тернарным оператором а с классом строки.
const char *s = String("Abcd");
будет падать ничуть не хуже.
Спасибо за статью. То что тернарный оператор может работать как lvalue знал, а то что это поведение определяется общим типом — нет.
Я бы еще упомянул про опасности связанные с низким приоритетом тернарного оператора, которые с успехом были раскрыты в одном из постов PVS Studio. Ну и про то, что части оператора являются точками следования, тоже стоило сказать.
Я бы еще упомянул про опасности связанные с низким приоритетом тернарного оператора, которые с успехом были раскрыты в одном из постов PVS Studio. Ну и про то, что части оператора являются точками следования, тоже стоило сказать.
По поводу четвертого пункта, но почему не «return !true;»? :-)
P.S. Интересно, почему я не могу пользоваться тегом?
P.S. Интересно, почему я не могу пользоваться тегом?
Часто пользуетесь в своем коде подобным?
Знать это хорошо, но знание ради знания это онанизм.
Знать это хорошо, но знание ради знания это онанизм.
Вы не рассказали о самой интересной и малоизвестной фиче тернарного оператора — возможности использовать throw в нем.
Приведите, пожалуйста, пример того, где это может быть оправдано.
int foo() {
return valid ? some_state : throw std::logic_error();
}
«Оправданность» в данном случае — понятие субъективное. Да, этот код можно написать с if. И он, наверное, будет так понятнее.
Понятно, спасибо. Но с моей точки зрения это нехорошая практика. Выражение должно быть однозначное. Изначальный смысл тернарного оператора — выбор значения (тогда как условной конструкции — выбор ветви выполнения). Здесь же смешались в кучу кони, люди. Да, это компактнее, но стоит ли экономить на одном условии? Ради чего?
По своей сути это ничуть не лучше, чем выражение из недавней статьи про JavaScript:
которое является способом записи условия:
По своей сути это ничуть не лучше, чем выражение из недавней статьи про JavaScript:
!~utils.indexOf(adjacency, id) && adjacency.push(id);
которое является способом записи условия:
if (utils.indexOf(adjacency, id) >= 0)
adjacency.push(id);
В constexpr функциях, чтобы можно было ловить различные ошибки в переданных аргументах на этапе компиляции. Подробнее можно посмотреть тут: scrutator.me/post/2013/11/19/constant_expressions.aspx
Кстати, в C++14 можно будет использовать if в constexpr.
Ну и заодно, при разговоре об общих типах, не вредно упомянуть о том, что void является допустимым типом операндов. Т.е. можно писать так:
true ? (void)C() : (void)D();
Багфикс:
class String
{
public:
const char* operator() (arguments-of-the-function-operator-must-go-here);
operator const char*() const; // оператор приведения типа
};
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»;
А это точно не будет генерировать код при отключенном логере?
Я так понимаю, это равносильно
if (false) fake_logger() << "blah-blah";
Точно? Не вижу я там «if (false)» Т.е. fake_logger дёргаться и параметры для "<<" него будут готовиться и если там строки, то это тяжёлые операции, которые будут выполнятся даже при отключённом логере.
LOGGER() << "blahblahblah";
Раскроется в:
(true) ? void() : fake_logger() << "blahblahblah";
что благодаря крайне высокому приоритету тернарного оператора эквивалентно:
(true) ? void() : (fake_logger() << "blahblahblah");
Так как до правой части дело не дойдёт, то и вычислений никаких там произведено не будет.
Чем это лучше, чем
define LOGGER() fake_logger()
?Спасибо за статью! Узнал много нового.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Секреты тернарного оператора