Подтвердить что ты не робот

Когда/Почему (если когда-либо), я должен думать о том, как делать общее программирование/мета-программирование

IMHO мне OOPS, шаблоны дизайна имеют смысл, и я смог применить их практически.

Но когда дело доходит до "универсального программирования/метапрограмм" для современного С++, я оставлен в замешательстве.

- Это новая парадигма программирования/дизайна?

- Он ограничен только "развитием библиотеки"? Если нет, то какие ситуации проектирования/кодирования требуют использования метапрограммирования/общего программирования.

- Используется ли использование шаблонов, я делаю общее программирование?

У меня много интересного по этой теме, но не полностью разбирайте БОЛЬШОЙ ИЗОБРАЖЕНИЕ. Также смотрите post.


После прочтения здесь до сих пор, до сих пор, я уверен (может быть, все еще не правильно):

a) Общее программирование и мета-программирование - это два разных понятия.

4b9b3361

Ответ 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