Комментарии 13
Если на шаблонах и функциях рекурсия пишется естественным способом (компилятор берёт на себя арифметику и ветвление), то на препроцессоре придётся как-то исхитряться.
Вот, казалось бы, BOOST_PP, практически промышленная библиотека, — а и то имеет внутренние ограничения "потомучто марамучто". Там нельзя сделать препроцессорный массив из более чем 20 элементов, потому что у разработчиков на 21-м нумерованном макросе контрол-вэ сломалось.
У каждого языка своя ниша и специализация. C++ явно небезопасен для того, чтобы на нем писать плагины к компилятору. А у js уже есть успешный опыт работы с древовидной DOM языка HTML.
Те же шаблоны C++ это по сути отдельный язык, лишь частично пересекающийся с C++. Вы не примените там if, while, for, не выделите память оператором new, не воспользуетесь классами какого нибудь Qt или WxWidgets.
Проблема а том, что этот язык получился случайно и не очень то удобен для программирования.
Я плохо говорю на плюсах, но в С на макросах можно реализовать if, while, for в boost.preprocessor или в Р99. Хотя это жуткое извращение заставлять фактически рефал-машину изображать из себя императивный ЯП.
Ох, если бы рефал-машину…
Вот если бы в качестве обязательного этапа трансляции был не cpp, а m4, например… (то это был бы ацкий ад).
Ох, если бы рефал-машину…У меня такие ассоциации: иммутабельность, чистота, подстановка. Собсно, из-за изначально заложенных подводных граблей при любой реализации for на макросах вылазит ужас типа
#define EVAL1024(x) (EVAL512(x), EVAL512(x))
а while разворачивается в аналог prototheads/Duff's device через макросы FOR (см.выше) и __line__
Вот если бы в качестве обязательного этапа трансляции был не cpp, а m4Спасибо, мы ещё помним sendmail. Аж по шкварнику мурашки пробежали.
Шаблоны задумывались как гигиенические макросы, а внезапно получилось то, что получилось.
А если мы добавим настоящие гигиенические макросы в стиле немерле или темплит-хаскела, то это вообще взрыв мозга получится.
Потому что найдутся способы и их тоже вывернуть мясом наружу, как это сделали с шаблонами.
constexpr unsigned f(unsigned n) {
return n < 2 ? f(n-1) + f(n-2);
}
Не, конечно, в разных контекстах одно и то же синтаксическое дерево будет резолвиться по-разному.
Даже без новомодных концептов:
#include <iostream>
char f(...);
const int a = sizeof(f(0)); // 1
short f(short);
const int b = sizeof(f(0)); // 2
int f(int);
const int c = sizeof(f(0)); // 4
int main() {
std::cout << a << " " << b << " " << c << std::endl;
}
Определение функции закрепляет контекст: где она определена, там она и будет вычисляться.
А два экземпляра одного и того же выражения, скопированные в разные места… следует рассматривать как два выражения, хоть и побуквенно совпадающие.
Мемоизация в compile time вычислениях в C++