Являются ли шаблоны C ++ просто прославленными макросами?

27

Из разных сравнений среди шаблонов C ++ и C # / обобщений Java, как этот

/programming/31693/what-are-the-differences-between-generics-in-c-and-java-and-templates-in-c/31929#31929

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

Затем я нашел некоторые другие факты, подтверждающие это

  • Я думал, что если шаблоны C ++ будут реализованы с помощью предварительной обработки, возникнут проблемы с динамическим связыванием (с использованием .dll). И быстрый поиск в Google поддержал это.

  • Другое дело, что целочисленные константы могут быть переданы в качестве аргументов шаблонам. И это даже поддерживает какую-то рекурсию. Но эта рекурсия не найдена в скомпилированной сборке / машинном коде. Управление рекурсией осуществляется во время компиляции путем генерации функций для каждого рекурсивного вызова и, таким образом, получения большего, но более быстрого исполняемого двоичного файла.

Хотя в отличие от макросов C, он обладает некоторыми превосходными возможностями. Но разве шаблон C ++ не реализован с какой-то предварительной обработкой? Как это реализовано в разных компиляторах C ++?

Gulshan
источник
19
Нет. Шаблоны C ++ компилируются.
Эдвард Стрэндж
2
Каково ваше определение «предварительной обработки»? А из "компиляции"? Достаточно широкое определение «предварительной обработки» может включать все, что делает компилятор; в конце концов, компилятор действительно просто обрабатывает исходный код, прежде чем он будет выполнен, не так ли?
Джеймс МакНеллис,
@James McNellis ИМХО, если вы можете просто отличить предварительную обработку от всего остального, что делается для компиляции, то достаточно понять мой вопрос. Для уточнения препроцессора
Гульшан
6
Если вы говорите об этой форме предварительной обработки, то нет, шаблоны C ++ - это не просто своего рода прославленный макрос.
Джеймс МакНеллис
1
Язык шаблонов фактически завершен, поэтому они представляют собой нечто большее, чем расширенные макросы.
davidk01

Ответы:

9

Шаблоны C ++ являются своего рода тупыми макросами Lisp (или даже более того, Scheme). Это полный по Тьюрингу язык, который оценивает во время компиляции, но он сильно ограничен, так как у него нет доступа к базовой среде C ++. Итак, да, шаблоны C ++ можно рассматривать как некую форму предварительной обработки, с очень ограниченным взаимодействием с генерируемым кодом.

SK-логика
источник
2
«но он строго ограничен, поскольку у этого языка нет доступа к базовой среде C ++». -- Что это означает? Я попытался разобрать это утверждение, но не получилось.
Quant_Dev
2
Хм, на самом деле ... github.com/kmichel/bf0x
Антон Голов
3
@ SK-logic: Кроме того, C ++ 11 - это C ++, если только вы (педантично) не рассматриваете разные версии одного и того же языка как разные языки.
Джон Пурди
3
@Jon Purdy, C ++ 11 не существовало (официально) к моменту получения этого ответа. В настоящее время пример был бы более сложным, например, декомпозиция структуры данных, использование библиотечной функции и т. Д.
SK-logic
1
@ SK-logic: Вы случайно не знакомы с реализацией C ++ с помощью Lisp-подобных макросов? Мне надоели ограничения шаблона. Пример синтаксического языка в стиле C ++ с мощной системой макросов в Haxe: haxe.org/manual/macros . (Мне это не помогает, потому что я использую C ++ для своей цели - программирование 8-битных микроконтроллеров; есть лучшие языки для всего остального).
pfalcon
41

Вероятно, самое большое отличие состоит в том, что макросы C расширяются на этапе предварительной обработки, прежде чем будет выполнена какая-либо другая компиляция, в то время как шаблоны C ++ являются частью компиляции. Это означает, что шаблоны C ++, помимо прочего, учитывают тип и ограничены областью применения и не являются простой текстовой заменой. Они могут компилироваться в реальные функции и, следовательно, избегать большинства проблем, возникающих в макросах. Понимание типов означает, что они могут быть общими или специализированными: например, легко обеспечить функцию swapшаблона и легко написать специализации, которые хорошо работают, даже если объекты управляют кучей памяти.

Следовательно: шаблоны C ++ не подвергаются предварительной обработке в том же смысле, что и макросы, они не являются своего рода макросом C, и невозможно использовать макросы C для дублирования того, что делают шаблоны.

Шаблоны живут в заголовочных файлах, а не в связанных библиотеках, правда, но если вы предоставляете .dll, вы, вероятно, также предоставляете файл заголовка для его использования.

Дэвид Торнли
источник
12
Им не нужно жить в заголовочном файле (это самый простой способ их использования). Вы можете определить их в исходном файле и вручную принудительно создать экземпляр шаблона в исходном файле (модуль компиляции). При связывании экземпляры будут подбираться как обычно (это методика ограничения шаблонов конкретными типами и недопущения использования всех универсальных типов).
Мартин Йорк
@Martin: я не уверен, что этот метод (хотя и поддерживается) на самом деле явно поддерживается стандартом. В противном случае все компиляторы уже были бы exportреализованы. Я знаю, что это работает для функций, но я сомневаюсь, что это работает для классов: как бы вы узнали их размер?
Матье М.
@Matthieu M: Это не имеет ничего общего с ключевым словом экспорта. Он имеет дело с "явным" созданием шаблона и хорошо определен в стандарте.
Мартин Йорк,
2
@Matthieu M .: Если компилятор знает сигнатуру функции и компоновщик может найти реализацию, все круто. Это применяется независимо от того, является ли функция шаблоном. На практике они, как правило, живут в заголовочных файлах, потому что принудительное создание конкретных экземпляров, как правило, требует больше работы, чем стоит, но Мартин прав, когда замечает альтернативу.
Дэвид Торнли
Я знаю, что это работает, конечно, для специализированных функций. Однако я также совершенно уверен, что это не работает для классов, что было моей точкой зрения. Я думаю, что это работает и для методов из специализированных классов, но я не знаю, является ли это стандартным.
Матье М.
5

Имеет ли значение, как они реализованы? Ранние компиляторы C ++ были просто препроцессорами, которые передавали код в компилятор ac, это не значит, что C ++ - просто прославленный макрос.

Шаблоны устраняют необходимость в макросах, предоставляя более безопасный, более эффективный и специализированный (даже я не думаю, что это настоящее слово) способ реализации кода для нескольких типов.

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

Мартин Беккет
источник
Я не сказал, что C ++ - это прославленный макрос. Я очень восхищаюсь C ++. Просто быть любопытным.
Гюльшан
2
@Gulshan: Нет, ты ничего не сказал об этом. Тем не менее, именно так работали ранние компиляторы C ++ (за исключением того, что CFront был чем-то вроде компилятора, а не просто препроцессора макросов), и ваши утверждения о шаблонах C ++ примерно так же применимы к самому раннему C ++.
Дэвид Торнли
CFront скомпилирован из C ++ в C. Линия между препроцессором и компилятором четко определена: компилятор пытается понять свои входные данные - посредством синтаксического анализа, построения AST и т. Д., В то время как препроцессор этого не делает, например, используя только текстовую замену или замену токена.
Джон Пурди
1
Я думаю, что Дэвид имел в виду, что существует базовое подмножество C ++ и что шаблоны можно рассматривать как некий макрос, который используется для генерации программы в этом подмножестве, который затем может быть скомпилирован как дополнительная, отдельная стадия.
Джорджио
5

Есть некоторые различия; например, шаблоны могут использоваться для создания экземпляра перегрузки функции, когда это необходимо, в то время как с макросами вам придется расширять макрос один раз для каждой возможной перегрузки, чтобы сделать его видимым для компилятора, так что вы получите много неиспользованного кода.

Другое отличие состоит в том, что шаблоны уважают пространства имен.

Саймон Рихтер
источник
2

ИМХО, шаблоны C ++ и макросы C предназначены для решения двух совершенно разных задач. Исходная библиотека стандартных шаблонов C ++ представляла собой механизм для чистого отделения контейнерных классов (массивов, связанных списков и т. Д.) От универсальных функций, обычно применяемых к ним (таких как сортировка и конкатенация). Наличие абстрактных представлений эффективных алгоритмов и структур данных приводит к более выразительному коду, потому что было значительно меньше догадок о том, как лучше всего реализовать функцию, работающую с конкретным фрагментом данных. Макросы C были в большей степени соответствуют тому, что обычно можно увидеть в макросах Lisp, в том смысле, что они предоставляли средство для «расширения» языка с помощью встроенного кода. Круто то, что стандартная библиотека C ++ расширила функциональность шаблонов, чтобы охватить подавляющее большинство того, для чего мы используем #define в C.

Марк
источник