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

Скопируйте условно отформатированные ячейки в Word (используя CTRL + C, CTRL + V). Скопируйте их обратно в Excel, сохраняя исходное форматирование. Теперь условное форматирование потеряно, но у вас все еще есть цвета, и вы можете проверить RGB, выбрав «Главная»> «Цвет заливки» (или «Цвет шрифта»)> «Другие цвета».

17
задан Nicol Bolas 10 March 2012 в 04:33
поделиться

9 ответов

Метапрограммирование - довольно экзотическая тема. Об этом интересно узнать, это мощный инструмент, который иногда может оказаться полезным. Но это никогда не будет наиболее часто используемым инструментом в вашем наборе инструментов. Иногда вам может потребоваться, чтобы ваш код воздействовал на ряд несвязанных типов с различными свойствами, и именно здесь на помощь приходит метапрограммирование. Приложив немного хитрости, вы можете написать перегрузку функции, которая доступна только в том случае, если тип аргумента является целым. , или если это указатель, или если это тип X, Y или Z (возможно, игнорируя константу Z).

По сути, это программирование с типами. Обычно ваша программа может делать такие вещи, как брать два числа и выдавать третье число или сообщать вам, удовлетворяет ли число какому-либо требованию. Метапрограммирование может принимать два типа и порождать третий тип, или сказать вам, удовлетворяет ли тип какому-либо требованию. И да, это, вероятно, в основном полезно при разработке библиотек. Но опять же, большая часть кода может считаться библиотечным кодом . Вы могли бы сказать, что все, что находится за пределами вашей функции main (), - это код библиотеки.

Обычно, если вы хотите решить проблему с помощью метапрограммирования, вы, вероятно, захотите использовать соответствующие библиотеки ускорения для выполнения тяжелой работы. Boost.TypeTraits и, конечно, Boost.Mpl могут действительно упростить вам жизнь. Но это не то, что вам нужно знать, и это не то, что вам, вероятно, понадобится очень часто.

Общее программирование связано (и в некоторых случаях может использоваться метапрограммирование под капотом, чтобы стать действительно общим , например, стандартная библиотека использует легкое метапрограммирование для превращения необработанных указателей в действительные итераторы, что требуется для того, чтобы концепция «итератора» была универсальной), но не совсем то же самое. И это гораздо более широко используется.

Каждый раз, когда вы создаете экземпляр std :: vector , вы используете универсальное программирование. Каждый раз, когда вы используете пару итераторов для обработки последовательности значений, вы используете универсальное программирование. Общее программирование - это просто идея о том, что ваш код должен быть как можно более универсальным и должен работать независимо от того, какие типы в него включены. Std :: vector не требует, чтобы содержащийся тип реализовывал интерфейс «ICanBeConhibited» (помните, как Java требует, чтобы все было производным от Object, чтобы оно сохранялось в классе контейнера? Это означает, что примитивные типы помещаются в коробку, и что мы теряем безопасность типов. Это не универсальное и бессмысленное ограничение.)

Код для итерации последовательности с использованием итераторов является универсальным и работает с любыми типами итераторов или даже с простыми указателями.

Универсальный. программирование очень широко используется и часто может в значительной степени заменить ООП. (см. приведенный выше пример. Зачем мне писать контейнер, который требует вложенных типов для реализации интерфейса, если я могу избежать этого ограничения?)

Часто, когда вы используете интерфейсы в ООП, это не позволяет типу изменения во время выполнения (хотя, конечно, это тоже случается время от времени), но чтобы вы могли поменять местами другой тип во время компиляции (возможно, внедряя фиктивный объект во время тестов вместо использования полноценной реализации) или просто разделить два класса. Универсальное программирование может сделать это, не требуя от вас утомительной работы по определению и поддержке интерфейса. В этих случаях универсальное программирование означает, что вам нужно писать и поддерживать меньше кода, и вы получаете лучшую производительность и лучшую безопасность типов. Так что да, вы определенно должны чувствовать себя как дома с общим программированием. C ++ - не очень хороший язык ООП. Если вы хотите строго придерживаться ООП, вам следует переключиться на Java или другой язык, более ориентированный на ООП. C ++ позволяет писать объектно-ориентированный код, но часто это не лучшее решение. Есть причина, по которой почти вся стандартная библиотека полагается на универсальное программирование, а не на ООП. В стандартной библиотеке очень мало наследования или полиморфизма. Им это было не нужно, и без него код стал проще и мощнее.

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

Я думаю, что xtofl действительно прибил. it: Общее программирование заключается в том, чтобы ваш код не знал о типах. (Std :: vector не заботится о , или нужно знать , какой тип в нем хранится. Он просто работает.)

Метапрограммирование, с другой стороны, касается вычисления типов. Учитывая типы T0 и T1, мы можем определить тип T2, точно так же, как мы можем, учитывая целые числа N0 и N1, В обычном коде, если у вас есть целые числа N0, N1 и N2, вы можете создать std :: vector, содержащий эти три значения. Затем я могу использовать какой-либо другой алгоритм для вычисления индекса, а затем извлечь значение, хранящееся в этом месте в векторе.

Учитывая типы T0, T1 и T2, мы можем создать mpl :: vector, содержащий эти три типы . Теперь я могу использовать другой алгоритм для вычисления индекса во время компиляции и извлечения типа , хранящегося в этом месте вектора.

30
ответ дан 30 November 2019 в 10:12
поделиться

Вам действительно нужно различать универсальное программирование (которое не знает типов) и метапрограммирование, которое является совершенно законным способом выполнения вычислений в системе типов.

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

Метапрограммирование применимо в совершенно другой области. Эта область, действительно, довольно новая и требует вашего собственного изучения. Это тоже весело!

Одним из очень полезных и распространенных паттернов метапрограммирования является концепция Traits / Policy.

11
ответ дан 30 November 2019 в 10:12
поделиться

Я никогда не видел твердого соглашения в любом случае.

Тем не менее, совершенно уверен, что что бы вы ни выбрали, кто-то другой будет на 100% уверен, что должно быть наоборот. Итак, лучшая идея - терпеть все, что установлено в любом случае.

В мире .NET, Path.Combine () дает вам способ справиться с этим - есть эквиваленты в других средах, начиная с файлов cmd и выше.

(подумайте о контейнерах STL, auto_ptrs и т. д.), для чего были разработаны шаблоны C ++, и важно «метапрограммирование шаблонов» (использование системы шаблонов, чтобы компилятор эффективно «запускал алгоритмы» за вас).

I ' m все в пользу первого, но мне трудно увидеть реальную пользу от последнего.

10
ответ дан 30 November 2019 в 10:12
поделиться

Для продвинутых шаблонов и техник я рекомендую: Современный дизайн C ++ , Андрей Александреску

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

5
ответ дан 30 November 2019 в 10:12
поделиться

Когда:

Шаблонное метапрограммирование - это способ написания программ, которые интерпретируются компилятором. Это на один уровень абстракции выше. С ним можно делать самые разные странные и забавные вещи. Библиотеки boost содержат множество примеров:

  • Не нравится, что c ++ статически типизирован? Используйте boost :: any.
  • Любите лямбда-исчисление, но нужно ли вам C ++? Используйте boost: lambda.
  • У вас есть EBNF и нужен синтаксический анализатор? Используйте boost :: spirit.

Почему:

Это круто. Вы можете произвести впечатление на свидания (возможно).

3
ответ дан 30 November 2019 в 10:12
поделиться

Когда у вас есть достаточно времени и вы хотите воспроизвести .

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

1
ответ дан 30 November 2019 в 10:12
поделиться

Простой пример:

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);

поменять местами значения 2 переменных одного типа.

С помощью шаблонов мы избегаем явного создания функций для различных типов комбинаций , например эти:

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 .

1
ответ дан 30 November 2019 в 10:12
поделиться

Думаю, если вы не разработчик библиотеки, тогда о метапрограммировании шаблонов лучше забыть. Я считаю, что он бесполезен в производственном коде, создает больше проблем, а затем приносит пользу: «Как только вы начнете его использовать, вы потеряете гибкость, привязанную к этому решению. После того, как вы начал его использовать. И это проблема, поскольку шаблоны недостаточно гибкие ».

PS Я, конечно, не имею в виду контейнеры шаблонов, свопы, ... но код, подобный Александреску

0
ответ дан 30 November 2019 в 10:12
поделиться

Один ответ, который еще не был дан: хотя универсальное программирование и метапрограммирование действительно сильно отличаются друг от друга, они оба были разработаны для решения (по существу) та же проблема: как избавиться от шаблона. Они также воплощены не в одном, а в двух акронимах принципов программной инженерии: DRY (не повторяйтесь) и DIE (дублирование - зло) . Это современная перефразировка Бритвы Оккама , то есть, что «сущности не должны умножаться сверх необходимости» ( entia non sunt multiplicanda praeter needitatem ). [Кто знал, что логики 14 века могут придумать что-то полезное для разработки программного обеспечения 21 века?].

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

Оказывается, эти две техники можно использовать вместе даже для довольно необычных вещей. См. Пример Многоступенчатое программирование с функторами и монадами: устранение накладных расходов на абстракцию из универсального кода . Но если вы думаете, что STL - это страшно, лучше не смотрите на него ...

4
ответ дан 30 November 2019 в 10:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: