Блог пользователя caustique

Автор caustique, 14 лет назад, По-русски
Зачем в определении макросов опытные участники пишут #define all(v) (v).begin(), (v).end(), обрамляя название контейнера в дополнительные скобки? То же самое с переменной в цикле for: #define REP(i,n) for (int (i)=0; (i)<n; (i)++)
В каких случаях это может помочь?
  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
как я понимаю, это нужно для того, чтобы приоритеты операций выполнялись правильно.
а иначе, могут выползти неожиданные спецэффекты, которые КРАЙНЕ непросто будет отловить.

в любом случае, лучше перестраховаться
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Например, такая штука не скомпилируется:

#define all(v) v.begin(), v.end()
vector<int> x;
vector<int>* p = &x;
sort(all(*p));

Во втором случае, конечно, скобочки не нужны, но их все равно ставят во всех макросах во избежание досадных неприятностей типа такого:

#define sqr(n) n*n
cout << sqr(3+3)
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Кстати, вокруг n скобочки лучше бы поставить :D

    int c = 3;
    REP(i, c>0 ? c : c+1)
        cout << i << endl;
  • 14 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится
    И перед скобочками еще неплохо бы (int) написать, а то могут быть неприятные спецэффекты, как, например, в таком коде:

    vector<int> v;
    REP(i,v.size()-1)
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      А мне больше нравятся эти спецэффекты, чем потенциальное неявное приведение типов без предупреждения :) Для векторов можно сделать, например, #define forv(i,v) REP(i,((int).v.size())-1).
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        что плохого в приведении size_t к инту? все равно контейнеры STL не будешь делать размера больше 2^31, с ними не поработаешь.

        так что, на мой взгляд, эти варнинги тупы, приведение адекватное и нужное, и позволяют избежать тупых ошибок с переполнением
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Для контейнеров конечно. Я имею в виду REP вообще, он может вызываться с каким-нибудь выражением в качестве верхней границы, оно может случайно оказаться, например, типа double, тогда ворнинг поможет это заметить.
          • 14 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Упс, инт с даблом и без преобразования сравнится без предупреждений, неподходящий пример :)
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
#define sqr(a) (a*a)

cout << sqr(2+2);

что бы ты хотел видеть :
cout << 4 * 4;
а, что в итоге:
cout << 2 + 2 * 2 + 2;
естесно 2 * 2 + 2 + 2 далеко не 4 * 4.
так-то.