Когда/Почему (если когда-либо), я должен думать о том, как делать общее программирование/мета-программирование
IMHO мне OOPS, шаблоны дизайна имеют смысл, и я смог применить их практически.
Но когда дело доходит до "универсального программирования/метапрограмм" для современного С++, я оставлен в замешательстве.
- Это новая парадигма программирования/дизайна?
- Он ограничен только "развитием библиотеки"? Если нет, то какие ситуации проектирования/кодирования требуют использования метапрограммирования/общего программирования.
- Используется ли использование шаблонов, я делаю общее программирование?
У меня много интересного по этой теме, но не полностью разбирайте БОЛЬШОЙ ИЗОБРАЖЕНИЕ.
Также смотрите post.
После прочтения здесь до сих пор, до сих пор, я уверен (может быть, все еще не правильно):
a) Общее программирование и мета-программирование - это два разных понятия.
Ответы
Ответ 1
Метапрограммирование - довольно экзотическая тема. Это интересно узнать, это мощный инструмент, и иногда вы можете найти его полезным. Но это никогда не будет наиболее часто используемым инструментом в вашем наборе инструментов. Иногда вы можете захотеть, чтобы ваш код действовал по целому ряду несвязанных типов с разными свойствами и что там, где происходит метапрограммирование. С небольшим количеством обмана вы можете написать перегрузку функции, доступной только в том случае, если тип аргумента является интегральным, или если это указатель, или если это либо тип X, Y, либо Z (возможно, игнорирование константы на Z).
Это, по сути, программирование с помощью типов. Обычно ваша программа может делать что-то вроде двух чисел и производить третье число или рассказать вам, удовлетворяет ли число некоторым требованиям. Метапрограммирование может принимать два типа и производить третий тип, или сказать вам, соответствует ли тип требованиям. И да, это, вероятно, в основном полезно в развитии библиотеки. Но опять же, большинство кодов можно считать библиотечным кодом. Можно сказать, что все, что находится вне вашей функции main(), является библиотечным кодом.
Обычно, если вы хотите решить проблему с помощью метапрограммирования, вы, вероятно, захотите использовать соответствующие библиотеки boost для тяжелого подъема. Boost.TypeTraits и, конечно же, Boost.Mpl действительно могут упростить вам вещи. Но это не то, что вам нужно знать, и это не то, что вам может понадобиться очень часто.
Общее программирование связано (и может в некоторых случаях использовать метапрограммирование под капотом, чтобы стать действительно общим, например, стандартная библиотека использует прикосновение метапрограммирования, чтобы превратить исходные указатели в действительные итераторы, которые необходимы для концепции "итератор" быть общим), но не совсем одно и то же. И это гораздо более широко используется.
Каждый раз, когда вы создаете экземпляр std::vector
, вы используете универсальное программирование. Каждый раз, когда вы используете пару итераторов для обработки последовательности значений, вы используете универсальное программирование. Общее программирование - это просто идея о том, что ваш код должен быть как можно более общим, и должен работать независимо от того, какие типы помещаются в него. A std::vector не требует наличия скрытого типа для реализации интерфейса "ICanBeContained" (помните, как Java требует, чтобы все, что должно быть получено из Object, чтобы оно хранилось в классе контейнера? Что означает, что примитивные типы получаются в коробке, и что мы теряем безопасность типов, что не является общим, и это бессмысленное ограничение.)
Код для итерации по последовательности с использованием итераторов является общим и работает с любым типом итераторов или даже с простыми указателями.
Общее программирование очень полезно и часто может в значительной степени заменить ООП. (см. приведенный выше пример. Почему я должен писать контейнер, который требовал, чтобы содержащиеся типы реализовали интерфейс, если я могу избежать этого ограничения?)
Часто, когда вы используете интерфейсы в ООП, это не должно позволять типу изменять во время выполнения (хотя, разумеется, это время от времени тоже), но чтобы вы могли меняться под другим типом во время компиляции ( возможно, вводить макет объекта во время тестов, а не использовать полноценную реализацию) или просто отделить два класса. Общее программирование может сделать это, не выполняя утомительную работу по определению и поддержанию интерфейса. В этих случаях универсальное программирование означает, что вам нужно писать и поддерживать меньше кода, и вы получаете лучшую производительность и лучшую безопасность типов. Так что да, вы определенно должны чувствовать себя как дома с общим программированием. С++ - не очень хороший язык ООП. Если вы хотите строго придерживаться ООП, вы должны переключиться на Java или еще на более OOP-фиксированный язык. С++ позволяет писать OO-код, но часто это не лучшее решение. Причина в том, что почти вся стандартная библиотека опирается на родовое программирование, а не на ООП. В стандартной библиотеке очень мало наследования или полиморфизма. Они им не нужны, и код стал проще использовать и более мощным без него.
И чтобы ответить на ваши другие вопросы, да, общее программирование в значительной степени является отдельной парадигмой. Метапрограммирование шаблонов не является. Это довольно специфический метод манипулирования системой типов, и он очень хорош в решении небольшого числа проблем. Чтобы считаться парадигмой, я думаю, что она должна быть гораздо более полезной, и вы можете использовать ее в основном для всего, как функциональное, OO или общее программирование.
Я думаю, что xtofl действительно прибил его: Generic-программирование - это создание вашего типа кода - не осознавая. (A std::vector не заботится, или нужно знать, какой тип хранится в нем. Он просто работает.)
Метапрограммирование, с другой стороны, относится к вычислениям типа. Учитывая тип T0 и T1, мы можем определить тип T2, как и мы можем, учитывая целые числа N0 и N1, мы можем определить N2, который является суммой N0 и N1.
У библиотеки Boost.Mpl есть очевидный пример этого.
В вашем обычном коде, если у вас есть целые числа N0, N1 и N2, вы можете создать std::vector, содержащий эти три значения. Затем я могу использовать какой-либо другой алгоритм для вычисления индекса, а затем извлечь значение, сохраненное в этом месте в векторе.
Учитывая типы T0, T1 и T2, мы можем создать вектор mpl::, содержащий эти три типа.
Теперь я могу использовать какой-либо другой алгоритм для вычисления индекса во время компиляции и извлечь тип, сохраненный в этом месте в векторе.
Ответ 2
Вам действительно нужно различать родовое программирование (которое недобросовестно) и метапрограммирование, что является вполне законным способом делать вычисления в системе типов.
Общее программирование очень полезно, когда вы найдете обобщаемый шаблон во множестве кода. Если различие в шаблоне лежит не только в переменных значениях, но и в разных типах, универсальное программирование полезно для реорганизации кода.
Метапрограммирование применимо в совершенно другом домене. Этот домен, действительно, совершенно новый и нуждается в некотором изучении вашего собственного. Это тоже весело!
Один очень полезный и общий шаблон метапрограммирования - это концепция "Черты/политика".
Ответ 3
С++ Template metaprogramming - это мощный метод обфускации кода, применимый к целому ряду приложений:
- Если вы хотите написать код, который никто другой в вашей команде не может понять
- Если вам нужен код, который вы не сможете понять через 7 дней после его написания
- Когда производительность кода важнее для вас, чем ремонтопригодность
- Если вы хотите иметь возможность перечислить "метапрограммирование шаблонов" как навык в вашем резюме.
- Когда вам нужно написать код, который вряд ли будет работать на многих компиляторах реального мира.
- Если вы предпочитаете использовать лезвия бритвы, чем использовать макросы препроцессора
Еще один случай:
- Если вы хотите знать, как работают библиотеки Boost под капотом, или вы хотите внести в них вклад.
Различие между "универсальным программированием" (думаю, STL-контейнеры, auto_ptrs и т.д.), которые были разработаны для создания шаблонов С++ и "метапрограммирования шаблонов" (использование системы шаблонов, чтобы заставить компилятор эффективно "запускать алгоритмы" для вы).
Я все в пользу первого, но мне трудно увидеть реальные выгоды от последних.
Ответ 4
Для расширенных шаблонов и методов я рекомендую: Современный дизайн С++, Андрей Александреску
С++ - это жесткий язык, практически не имеющий возможности интроспекции времени исполнения. Многие проблемы, с которыми вы столкнетесь, могут быть решены с помощью шаблонов. Кроме того, язык шаблонов завершается, что позволяет создавать сложные структуры данных и предварительно вычислять значения во время компиляции, между прочим.
Для многих сценариев это может быть больше проблем, чем это стоит.
Ответ 5
Когда:
Мета-программирование шаблонов - это способ написания программ, которые интерпретируются компилятором. Это один уровень абстракции выше. Вы можете делать с ним всевозможные странные и причудливые вещи. Библиотеки ускорения содержат много примеров:
- Не нравится, что С++ статически типизирован? Использовать boost:: any.
- Любите лямбда-исчисление, но вы должны С++? Используйте boost: lambda.
- Есть ли EBNF и нужен парсер? Используйте boost:: spirit.
Почему:
Это круто. Вы можете произвести впечатление на свои даты (возможно).
Ответ 6
Один ответ, который еще не дан: хотя универсальное программирование и метапрограммирование действительно являются совершенно разными методами друг от друга, они оба были предназначены для решения (по существу) той же проблемы: как избавиться от шаблона. Они также воплощены не только в одном, но и в двух аббревиатурах принципов разработки программного обеспечения: DRY (не повторяйте себя) и DIE (дублирование - зло). Это современная перефразировка Оккамская бритва, т.е. Что "сущности не должны умножаться за пределы необходимости" (entia non sunt multiplicanda praeter necessitatem), [Кто знал, что логики 14-го века могут придумать что-то полезное для разработки программного обеспечения 21-го века?].
В любом случае, точка обоих методов заключается в том, чтобы найти способы унификации кодов, которые "почти одинаковы" в единый код параметризованного кода. В случае метапрограммного кода вы используете генерацию кода, поэтому метод включает в себя специализирование общей части кода (например, шаблона или, в целом, функции генерации кода) для конкретного случая. В общем случае программирования вы пытаетесь использовать систему типов, чтобы распознать, что разные фрагменты кода "одинаковы", а затем использовать диспетчеризацию типа для специализации.
Оказывается, эти два метода можно даже использовать вместе, чтобы делать довольно интересные вещи. См. Многоступенчатое программирование с функторами и монадами: устранение абстракции накладных расходов из общего кода для примера. Но если вы считаете, что STL страшно, лучше не смотреть на него...
Ответ 7
Если у вас осталось довольно много времени и хотите для воспроизведения.
Когда вам нужно повысить свой алгоритм и не хотите накладных расходов от вызовов виртуальных функций, вы можете заменить привязку времени выполнения с привязкой времени компиляции.
Ответ 8
Простой пример:
template<typename T>
void
swap(T& var1, T& var2)
{
T var3 = var1;
var1 = var2;
var2 = var3;
}
int a = 2;
int b = 3;
swap(a, b);
float c = 400.0f;
float d = 500.0f;
swap(c, d);
свопите значения двух переменных, имеющих один и тот же тип.
С помощью шаблонов мы избегаем экспликации, создаем функции для различных комбинаций типов, таких как:
void
swap(int& var1, int& var2)
{
int var3 = var1;
var1 = var2;
var2 = var3;
}
void
swap(float& var1, float& var2)
{
float var3 = var1;
var1 = var2;
var2 = var3;
}
Вышеуказанные функции будут созданы автоматически компилятором, в моем примере, если swap() вызывается где-то в коде с переменными int или float.
Ответ 9
Я думаю, если вы не разработчик библиотеки, тогда лучше забыть о метапрограммировании шаблонов. Я верю, что это бесполезно в производственном коде, давая больше проблем, а затем извлекает выгоду: "Как только вы начали использовать его, вы теряете гибкость, привязанную к этому решению. Очень сложно уйти от шаблонного кода после вас начал использовать его, и это проблема, поскольку шаблоны недостаточно гибкие".
P.S. Конечно, я не имею в виду шаблонные контейнеры, свопы, но код, похожий на Alexandrescu