Так часто приходится писать такой код:
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)


  1. neolink
    26.05.2015 12:57
    +59

    жесть, мало того что люди путаются в пост и пре инкрементах, теперь ещё и головастики…
    и да код стал ГОРАЗДО понятнее


  1. rafuck
    26.05.2015 13:02
    +35

    Ужас какой. Так бы и то было лучше: "~-y, ~+y". Но все равно, сам лично это в жизни не напишу.


    1. MacIn
      26.05.2015 16:47
      +1

      Там есть комменты, почему ~+ не сработает, посмотрите саму статью в блоге.


  1. dmitrmax
    26.05.2015 13:04
    +19

    Думаю, что если приживуться, то название у них будет одно — операторы-сперматозоиды


  1. KReal
    26.05.2015 13:07
    +13

    Поклонники Оберона негодуют!


  1. jcmvbkbc
    26.05.2015 13:10
    +22

    Что-то поздно для первого апреля.
    ~-y и -~y — валидный С/С++ код, теперь эти выражения будут иметь другое значение?.. А, ок, я понял, значение то же самое.


    1. rafuck
      26.05.2015 13:21

      А если y не int?


      1. jcmvbkbc
        26.05.2015 13:22

        тогда ~ обломится.


  1. Xitsa Автор
    26.05.2015 13:11
    +9

    Я на всякий случай обращу внимание на два факта:

    1. Эти операторы работают во многих современных компиляторах Си++, а не только в Visual C++
    2. Внимательно читаем теги статьи


    1. dmitrmax
      26.05.2015 13:17
      +3

      На самом деле зря про дефайн написал. Всем ясно, что дополнительный синтаксический сахар (если бы он был) не включается дефайнами )


  1. datacompboy
    26.05.2015 13:11
    +3

    А, ну да. Вместо непонятного и сложного (y+1) теперь простой и понятный -~y.


  1. NeoCode
    26.05.2015 13:12
    +13

    Вообще-то хороший пост для первого апреля:)
    Данные операторы работают в любом компиляторе С++, даже в самом древнем, и основаны на том что операторы смены знака и битовой инверсии, записанные друг за другом, дают именно такой эффект — увеличение или уменьшение числа на единицу (в зависимости от порядка следования).


    1. 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
      


    1. Xitsa Автор
      26.05.2015 13:25
      +8

      Они на самом деле не кроссплатформенные, так как работают только на числах в дополнительном коде.


      1. dmitrmax
        26.05.2015 13:30
        +1

        А реально приходилось работать на архитектурах, где это не так? Вопрос без подкола, просто интересно, ибо я о таких не знаю.


        1. Xitsa Автор
          26.05.2015 13:56
          +1

          Про машины с числами в обратном коде я знаю только про UNIVAC, но стандарт явно отказывается от указания способа представления числа со знаком, так что гарантировать их работу нельзя.


  1. Lerg
    26.05.2015 13:14
    +3

    Ждём Emoji в качестве операторов.


    1. jcmvbkbc
      26.05.2015 13:21
      +6

      уже сегодня в C++ можно писать

      int с[:>={
        0
      };
      

      Справа от слова int стоит улыбающийся человечек в шапке с помпоном.


  1. impwx
    26.05.2015 13:17
    +23

    От создателей оператора приближения к нулю (x --> 0), операторы-головастики. Уже сегодня в любой версии любого компилятора. Попробуйте и вы!


  1. eta4ever
    26.05.2015 13:20
    +28

    (?°?°)?????
    Throw Exception.


    1. Ryotsuke
      26.05.2015 13:43
      +26

      T--T ?(°—°?)
      Catch


      1. eta4ever
        26.05.2015 13:51
        +13

        Вообще, большой простор, не только для C. Вот для bash отличный touch: ( • )( • )?(????)


        1. 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, например


          1. eta4ever
            26.05.2015 14:14
            +1

            Это эпично.


          1. vlreshet
            26.05.2015 14:47

            Мой JS ругается на этот код, что я делаю не так?

            пруф
            image


            1. domix32
              26.05.2015 16:27
              +3

              Хабр что-то меняет в тексте. Балуйтесь


              1. vlreshet
                26.05.2015 17:33

                Спасибо за столь замечательную ссылку!

                P.S. вы не знаете как оно блин работает вообще?! ни черта не могу понять где там какой-нибудь eval запрятан, или что-то вроде того


                1. vlreshet
                  26.05.2015 17:40

                  А, всё, разобрался.


      1. dark_k3y
        26.05.2015 14:26

        В owl-lisp ?°—°? используется как оператор реверса. Пруф: github.com/aoh/owl-lisp/blob/master/owl/list.scm


    1. Halt
      27.05.2015 09:40
      +9

      (?°?°)?????
      Throw Exception.

      Мои глаза мне говорят что скорее это оператор DROP TABLE из мира SQL.


      1. eta4ever
        27.05.2015 11:56

        Изначально да, но он и здесь неплохо смотрится.


  1. Ryotsuke
    26.05.2015 13:23
    +24

    Новые затейливые вопросы на собеседованиях!

    -~~-3+-~~--~~--~~-2
    


    Синтаксический порошок какой-то


    1. eta4ever
      26.05.2015 13:25
      +5

      А вопрос — «угадайте язык».


      1. Ryotsuke
        26.05.2015 15:22

        Что интересно, выражение скорее всего валидно только в придуманной авторе версии C++ где "-~" это самостоятельный оператор, а не два.
        Яваскрипт, который вполне себе умеет и -~ и ~- конструкцию -~~--~~-2 не осиливает


        1. datacompboy
          26.05.2015 16:02
          +1

          просто нужны пробелы, иначе "--" распознаётся как декремент: ideone.com/ybmRx4


          1. AndrewN
            27.05.2015 15:07

            А лучше скобки


      1. Ryotsuke
        26.05.2015 15:21

        — duplicate -


    1. MichaelBorisov
      26.05.2015 13:47
      +2

      Похоже на Brainfuck


      1. eta4ever
        26.05.2015 13:51
        +10

        «Теперь вы можете Brainfuck прямо в C».


        1. Psychosynthesis
          26.05.2015 23:09

          Обоженет


          1. 6opoDuJIo
            27.05.2015 01:24
            +3

            %натурально поперхнулся чаем%


        1. int19h
          27.05.2015 02:25

          В C++ можно было и раньше, интерпретатор на шаблонах пишется на коленке. Правда, отжирает по паре гигабайт памяти на мало-мальски сложных программах, но, право же, это такая мелочь по сравнению с улучшенной читабельностью.

          А теперь, когда у нас есть еще и user-defined literals…


  1. dginz
    26.05.2015 13:28

    Подобный трюк очень подробно описывается в книге Ч. Петцольда «Код». Вернее, не как трюк, а как единственный разумный способ реализации разности в обычной системе записи (two’s complement) int-чисел.


  1. shock_one
    26.05.2015 13:38
    +1

    Теперь заживем.


  1. impwx
    26.05.2015 13:40
    +18

    Кстати, очень удобно, что оператор можно использовать многократно. Теперь записывать числа стало гораздо удобнее:

    int x = -~-~-~-~-~0; // x = 5
    


    1. vk2
      26.05.2015 14:09
      +9

      #include <stdio.h>
      int main(){ int $ = -~-~-~0; while ($ --> 0) putchar($["123"]); }
      


      1. rafuck
        26.05.2015 14:18

        Может быть всё же «123»[$]? :)


        1. senia
          26.05.2015 14:30
          +5

          Самое смешное, что нет.

          https://ideone.com/cWEr61

          a[b] == b[a] == *(a + b)


          1. rafuck
            26.05.2015 14:34
            +4

            Черт!.. Черт!!! Совсем мозги закостенели.


          1. 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+$[_])>>$,_[$]);
            }
            


            1. MacIn
              26.05.2015 21:26
              +1

              Вы мне монитор сломали. Кто ответит?


        1. vk2
          26.05.2015 14:32
          +2

          По стандарту эти записи эквивалентны.


    1. NeLexa
      26.05.2015 14:34

      Да вообще этот синтаксис прекрасно работает и в других ЯП. Попробовал навскидку на JS, Java, PHP, везде выводит 5.


  1. zenden2k
    26.05.2015 14:11
    -7

    Не надо портить строгий, простой и лаконичный язык своими изобретениями.


    1. shock_one
      26.05.2015 15:27
      +38

      Хорошо, не будем. А C++ можно?


  1. Hertz
    26.05.2015 17:00

    Я уж думал, вы тут расскажете про operator.(), а тут какая-то ересь :-)



  1. 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;
    }