Другая альтернатива, которая применима в некоторых случаях, является полиморфизмом времени компиляции с шаблонами. Полезно, например, когда Вы хотите сделать выбор реализации в начале программы, и затем использовать ее на время выполнения. Пример с полиморфизмом во время выполнения
class AbstractAlgo
{
virtual int func();
};
class Algo1 : public AbstractAlgo
{
virtual int func();
};
class Algo2 : public AbstractAlgo
{
virtual int func();
};
void compute(AbstractAlgo* algo)
{
// Use algo many times, paying virtual function cost each time
}
int main()
{
int which;
AbstractAlgo* algo;
// read which from config file
if (which == 1)
algo = new Algo1();
else
algo = new Algo2();
compute(algo);
}
тот же полиморфизм времени компиляции использования
class Algo1
{
int func();
};
class Algo2
{
int func();
};
template<class ALGO> void compute()
{
ALGO algo;
// Use algo many times. No virtual function cost, and func() may be inlined.
}
int main()
{
int which;
// read which from config file
if (which == 1)
compute<Algo1>();
else
compute<Algo2>();
}
Целочисленная арифметика? Запустите следующую программу, чтобы узнать:
#include "stdio.h"
int main() {
#if 1 + 1 == 2
printf("1+1==2\n");
#endif
#if 1 + 1 == 3
printf("1+1==3\n");
#endif
}
Ответ - «да», есть способ заставить препроцессор выполнять целочисленную арифметику, то есть использовать ее в условии препроцессора.
Обратите внимание, однако, что ваши примеры не являются целочисленной арифметикой. Я только что проверил, и препроцессор gcc не работает, если вы попытаетесь заставить его выполнять сравнения с плавающей запятой. Я не проверял, разрешает ли стандарт когда-либо арифметику с плавающей запятой в препроцессоре.
Обычное расширение макроса не оценивает целочисленные выражения, оно оставляет его компилятору, как можно увидеть, предварительно обработав (-E в gcc) следующие :
#define ONEPLUSONE (1 + 1)
#if ONEPLUSONE == 2
int i = ONEPLUSONE;
#endif
Результат: int i = (1 + 1);
(плюс, вероятно, некоторые вещи для указания имен исходных файлов, номеров строк и т. Д.).
Написанный вами код на самом деле не заставляет препроцессор производить какие-либо вычисления. #Define выполняет простую замену текста, поэтому определено следующее:
#define PI 3.1416
#define OP PI/100
Этот код:
if (OP == x) { ... }
становится
if (3.1416/100 == x) { ... }
, а затем он компилируется. Компилятор, в свою очередь, может выбрать такое выражение, вычислить его во время компиляции и создать код, эквивалентный этому:
if (0.031416 == x) { ... }
Но это компилятор, а не препроцессор.
Чтобы ответить на ваш вопрос, да, препроцессор МОЖЕТ делать некоторые арифметические операции. Это можно увидеть, если вы напишете что-то вроде этого:
#if (3.141/100 == 20)
printf("yo");
#elif (3+3 == 6)
printf("hey");
#endif
ДА , я имею в виду: он может выполнять арифметические операции :)
Как показано в 99 бутылок пива .
Да.
Я не могу поверить, что нет еще один связан с определенным победителем конкурса C. Этот парень реализовал ALU в препроцессоре с помощью рекурсивных включений. Здесь - реализация, а здесь - что-то вроде объяснения.
Теперь, при этом, вы не хотите делать то, что сделал этот парень. Это весело и все такое, но посмотрите на время компиляции в его файле подсказок (не говоря уже о том, что получившийся код невозможно поддерживать). Чаще люди используют препроцессор строго для замены текста, а вычисление арифметических операций с постоянными целыми числами происходит либо во время компиляции, либо во время выполнения.
Однако, как отмечали другие, вы можете выполнять некоторые арифметические действия в операторах #if.