*** ВНИМАНИЕ: Блог переехал на другой адрес - demin.ws ***

суббота, 25 сентября 2010 г.

Функции, указатели на них и оператор "?"

Был удивлен, когда компилятор С съел вот такой забавный способ условного вызова функций:

#include <stdio.h>
#include <math.h>
int main() {
  int i;
  for (i = 0; i <= 1; ++i) {
    float a = (i ? floor : ceil) (10.5);
    printf("%d: %f\n", i, a);
  }
  return 0;
}

Для С++ надо написать:

#include <stdio.h>
#include <cmath>
int main() {
  int i;
  typedef float (*f)(float);
  for (i = 0; i <= 1; ++i) {
    float a = (i ? (f)std::floor : (f)std::ceil) (10.5);
    printf("%d: %f\n", i, a);
  }
  return 0;
}

или

#include <stdio.h>
#include <cmath>
int main() {
  int i;
  for (i = 0; i <= 1; ++i) {
    float a = (i ? std::floorl : std::ceill) (10.5);
    printf("%d: %f\n", i, a);
  }
  return 0;
}

Все программы выводят:

0: 11.000000
1: 10.000000

8 комментариев:

  1. Странно, выглядит как отход от навязшей в зубах обратной совместимости с Сями. А почему собственно в С++ нужно так извращаться?

    ОтветитьУдалить
  2. bialix: ну а зачем писать проще, когда можно сложнее? =)

    ОтветитьУдалить
  3. А можно объяснение поведения оператора ?: в С?

    ОтветитьУдалить
  4. bialix, где вы видите извращение? Там ведь #include , значит, всё в namespace std, а не просто понакидано в глобальной области видимости. Сделайте как в C #include и всё будет совместимо.
    И, кстати, плюсы никогда не обещали быть _полностью_ совместимыми с прародителем.

    ОтветитьУдалить
  5. Nikita Marunyak, всё просто. Что floor, что ceil - это указатель на функцию. Это такой же тип, как int, и точно так же может использоваться, пусть даже и в тернарном операторе.

    ОтветитьУдалить
  6. Дебильный blogspot съел самое интересное...
    Там, где #include в первом случае cmath, во втором - math.h

    ОтветитьУдалить
  7. Могу предположить, что floor и ceil перегружены в С++, поэтому фактический указатель выявляется из типа параметра. А т.к. ( i ? floor : ceil ) не имеет такой подсказки, ничего и не заработает. Приводя же явно к флоату - подкаска опять на месте.

    ОтветитьУдалить
  8. @Дарк, bialix: Да, дело именно в наличии нескольких перегруженных вариантов, и не ясно, какую взять.

    @Nikita Marunya: ?: работает в С как и в С++. Вообще это весьма интересный оператор, так как он работает не только стадии выполнения, но и на стадии компиляции, например:

    #define COMPILE_TIME_ASSERT(x) \
    void __cta_proto__(int __cta_foo__[(x) ? 1 : -1])

    ОтветитьУдалить