x = (y + 1) % 10;
x = (y + 1) * (z - 1);
x = (double)(f(y) + 1);
Так как у операторов + и — такой низкий приоритет, то приходится постоянно заключать их в скобки, а это приводит к глубокому вложенному коду, который сложно понять.
В Visual Studio 2015 RC добавлена пара экспериментальных операторов, названных операторы–головастики. Они позволяют добавлять и вычитать единицу без необходимости прибегать к скобкам.
x = -~y % 10;
x = -~y * ~-z;
x = (double)-~f(y);
Они так названы, так как напоминают головастиков, которые плывут к или от значения. Тильда это голова, а минус — хвост.
Синтакс | Значение | Мнемоника |
---|---|---|
-~y | y + 1 | Головастик плывет к значению и делает его больше |
~-y | y — 1 | Головастик плывет от значения и делает его меньше |
Чтобы включить экспериментальную поддержку операторов–головастиков, добавьте в начале C++ файла:
#define __ENABLE_EXPERIMENTAL_TADPOLE_OPERATORS
Вот простая программа, которая демонстрирует применение операторов–головастиков:
#define __ENABLE_EXPERIMENTAL_TADPOLE_OPERATORS
#include <ios>
#include <iostream>
#include <istream>
int __cdecl main(int, char**)
{
int n = 3;
std::cout << "3 + 1 = " << -~n << std::endl;
std::cout << "(3 - 1) * (3 + 1) " << ~-n * -~n << std::endl;
return 0;
}
Помните, что эти операторы всё ещё экспериментальные. Они не являются официальной частью языка Си++, но вы можете поиграть с ними и оставить ваши замечания здесь.
При представлении чисел в дополнительном коде выполняется соотношение между арифметическими и побитовыми операциями:
-x = ~x + 1;
Из чего логично получается:
-~x = ~(~x) + 1 = x + 1;
~-x = (~-x + 1) - 1 = -(-x) - 1 = x - 1;
Т. е. никаких новых операторов–головастиков в Си++ не вводят, это просто шутка от Реймонда Чена.
Другие неочевидные операции в Си++ можно посмотреть на этой странице.
Комментарии (58)
dmitrmax
26.05.2015 13:04+19Думаю, что если приживуться, то название у них будет одно — операторы-сперматозоиды
Xitsa Автор
26.05.2015 13:11+9Я на всякий случай обращу внимание на два факта:
- Эти операторы работают во многих современных компиляторах Си++, а не только в Visual C++
- Внимательно читаем теги статьи
dmitrmax
26.05.2015 13:17+3На самом деле зря про дефайн написал. Всем ясно, что дополнительный синтаксический сахар (если бы он был) не включается дефайнами )
datacompboy
26.05.2015 13:11+3А, ну да. Вместо непонятного и сложного (y+1) теперь простой и понятный -~y.
NeoCode
26.05.2015 13:12+13Вообще-то хороший пост для первого апреля:)
Данные операторы работают в любом компиляторе С++, даже в самом древнем, и основаны на том что операторы смены знака и битовой инверсии, записанные друг за другом, дают именно такой эффект — увеличение или уменьшение числа на единицу (в зависимости от порядка следования).dmitrmax
26.05.2015 13:24+1А самое главное, что компилятор понимает этот трюк и оптимизирует его:
0000000000000000 <f>: 0: 8d 47 01 lea 0x1(%rdi),%eax 0000000000000010 <g>: 10: 8d 47 ff lea -0x1(%rdi),%eax
Xitsa Автор
26.05.2015 13:25+8Они на самом деле не кроссплатформенные, так как работают только на числах в дополнительном коде.
dmitrmax
26.05.2015 13:30+1А реально приходилось работать на архитектурах, где это не так? Вопрос без подкола, просто интересно, ибо я о таких не знаю.
Xitsa Автор
26.05.2015 13:56+1Про машины с числами в обратном коде я знаю только про UNIVAC, но стандарт явно отказывается от указания способа представления числа со знаком, так что гарантировать их работу нельзя.
impwx
26.05.2015 13:17+23От создателей оператора приближения к нулю (
x --> 0
), операторы-головастики. Уже сегодня в любой версии любого компилятора. Попробуйте и вы!
eta4ever
26.05.2015 13:20+28(?°?°)?????
Throw Exception.Ryotsuke
26.05.2015 13:43+26T--T ?(°—°?)
Catcheta4ever
26.05.2015 13:51+13Вообще, большой простор, не только для C. Вот для bash отличный touch: ( • )( • )?(????)
domix32
26.05.2015 14:14+11????= /`m?)? ~??? //*??`*/ ['_']; o=(???) =_=3; c=(???) =(???)-(???); (?Д?) =(???)= (o^_^o)/ (o^_^o);(?Д?)={???: '_' ,????: ((????==3) +'_') [???] ,???? :(????+ '_')[o^_^o -(???)] ,?Д??:((???==3) +'_')[???] }; (?Д?) [???] =((????==3) +'_') [c^_^o];(?Д?) ['c'] = ((?Д?)+'_') [ (???)+(???)-(???) ];(?Д?) ['o'] = ((?Д?)+'_') [???];(?o?)=(?Д?) ['c']+(?Д?) ['o']+(???? +'_')[???]+ ((????==3) +'_') [???] + ((?Д?) +'_') [(???)+(???)]+ ((???==3) +'_') [???]+((???==3) +'_') [(???) — (???)]+(?Д?) ['c']+((?Д?)+'_') [(???)+(???)]+ (?Д?) ['o']+((???==3) +'_') [???];(?Д?) ['_'] =(o^_^o) [?o?] [?o?];(???)=((???==3) +'_') [???]+ (?Д?) .?Д??+((?Д?)+'_') [(???) + (???)]+((???==3) +'_') [o^_^o -???]+((???==3) +'_') [???]+ (???? +'_') [???]; (???)+=(???); (?Д?)[???]='\\'; (?Д?).????=(?Д?+ ???)[o^_^o -(???)];(o???o)=(???? +'_')[c^_^o];(?Д?) [?o?]='\"';(?Д?) ['_'] ( (?Д?) ['_'] (???+(?Д?)[?o?]+ (?Д?)[???]+(???)+ (???)+ (???)+ (?Д?)[???]+(???)+ ((???) + (???))+ (???)+ (?Д?)[???]+(???)+ (???)+ ((???) + (???))+ (?Д?)[???]+(???)+ ((o^_^o) +(o^_^o))+ ((o^_^o) — (???))+ (?Д?)[???]+(???)+ ((o^_^o) +(o^_^o))+ (???)+ (?Д?)[???]+((???) + (???))+ (c^_^o)+ (?Д?)[???]+(???)+ ((o^_^o) — (???))+ (?Д?)[???]+(???)+ (???)+ (c^_^o)+ (?Д?)[???]+(???)+ (???)+ ((???) + (???))+ (?Д?)[???]+(???)+ ((???) + (???))+ (???)+ (?Д?)[???]+(???)+ ((???) + (???))+ (???)+ (?Д?)[???]+(???)+ ((???) + (???))+ ((???) + (o^_^o))+ (?Д?)[???]+((???) + (???))+ (???)+ (?Д?)[???]+(???)+ (???)+ (c^_^o)+ (?Д?)[???]+(???)+ (???)+ (???)+ (?Д?)[???]+(???)+ (???)+ ((o^_^o) — (???))+ (?Д?)[???]+(???)+ ((o^_^o) +(o^_^o))+ ((o^_^o) — (???))+ (?Д?)[???]+(???)+ ((o^_^o) — (???))+ (?Д?)[???]+((???) + (???))+ (???)+ (?Д?)[?o?]) (???)) ('_');
исполняемый JavaScript, напримерdark_k3y
26.05.2015 14:26В owl-lisp ?°—°? используется как оператор реверса. Пруф: github.com/aoh/owl-lisp/blob/master/owl/list.scm
Ryotsuke
26.05.2015 13:23+24Новые затейливые вопросы на собеседованиях!
-~~-3+-~~--~~--~~-2
Синтаксический порошок какой-тоeta4ever
26.05.2015 13:25+5А вопрос — «угадайте язык».
Ryotsuke
26.05.2015 15:22Что интересно, выражение скорее всего валидно только в придуманной авторе версии C++ где "-~" это самостоятельный оператор, а не два.
Яваскрипт, который вполне себе умеет и -~ и ~- конструкцию -~~--~~-2 не осиливаетdatacompboy
26.05.2015 16:02+1просто нужны пробелы, иначе "--" распознаётся как декремент: ideone.com/ybmRx4
MichaelBorisov
26.05.2015 13:47+2Похоже на Brainfuck
eta4ever
26.05.2015 13:51+10«Теперь вы можете Brainfuck прямо в C».
int19h
27.05.2015 02:25В C++ можно было и раньше, интерпретатор на шаблонах пишется на коленке. Правда, отжирает по паре гигабайт памяти на мало-мальски сложных программах, но, право же, это такая мелочь по сравнению с улучшенной читабельностью.
А теперь, когда у нас есть еще и user-defined literals…
dginz
26.05.2015 13:28Подобный трюк очень подробно описывается в книге Ч. Петцольда «Код». Вернее, не как трюк, а как единственный разумный способ реализации разности в обычной системе записи (two’s complement) int-чисел.
impwx
26.05.2015 13:40+18Кстати, очень удобно, что оператор можно использовать многократно. Теперь записывать числа стало гораздо удобнее:
int x = -~-~-~-~-~0; // x = 5
vk2
26.05.2015 14:09+9#include <stdio.h> int main(){ int $ = -~-~-~0; while ($ --> 0) putchar($["123"]); }
rafuck
26.05.2015 14:18Может быть всё же «123»[$]? :)
senia
26.05.2015 14:30+5Самое смешное, что нет.
https://ideone.com/cWEr61
a[b] == b[a] == *(a + b)andreybotanic
26.05.2015 20:33+1Хотел написать простой пример, показывающий эквивалентность этих выражений, но что-то слишком увлекся…
#include <stdio.h> int main() { int O=0,$=-~O,_[]={(++O)--,-~O++[_],-~O++[_],-~++O++[_]}; printf("%d%c%c%c%c%d",$[_],$<<_[_[_[$]]--],O=($<<-~_[O])+-~~-~_[$],O,(-~O+$[_])>>$,_[$]); }
NeLexa
26.05.2015 14:34Да вообще этот синтаксис прекрасно работает и в других ЯП. Попробовал навскидку на JS, Java, PHP, везде выводит 5.
nickolaym
26.05.2015 19:33+4Легко пропатчить старые версии студии и даже gcc — просто создайте и включите вот такой хедер
#ifndef __TADPOLE_H__ #define __TADPOLE_H__ template<class V> struct tadpole_minus { V v; tadpole_minus(V const& v) : v(v) {} V operator ~ () const { return v; } }; template<class V> struct tadpole_tilde { V v; tadpole_tilde(V const& v) : v(v) {} V operator - () const { return v; } }; template<class V> tadpole_minus<V> operator - (V v) { return (--v); }; template<class V> tadpole_tilde<V> operator ~ (V v) { return (++v); }; #endif // __TADPOLE_H__
Пример
#include <iostream> #include <string> #include "tadpole.h" int main() { std::string s = "alpha"; std::string::iterator i = s.begin() + 2; // теперь у итератора есть операторы "головастик туда" и "головастик сюда" std::cout << *~-~-i << *~-i << *i << *-~i << *-~-~i << std::endl; return 0; }
neolink
жесть, мало того что люди путаются в пост и пре инкрементах, теперь ещё и головастики…
и да код стал ГОРАЗДО понятнее