Шаблон метапрограммирования быстрее, чем эквивалентный код C? - PullRequest
11 голосов
/ 25 июля 2009

Является ли метапрограммирование шаблона быстрее, чем эквивалентный код C? (Я говорю о производительности во время выполнения):)

Ответы [ 8 ]

27 голосов
/ 25 июля 2009

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

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

Обычное использование для шаблонного метапрограммирования состоит в том, чтобы позволить типам использоваться в универсальном программировании, даже если они былине предназначен для этого.

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

В любом случае ...


Зависит от того, как вы определяете «эквивалентный код C».

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

Код, отображаемый здесь , например, вычисляет число в последовательности Фибоначчи во время компиляции.

Код C ++ 'unsigned long fib11 = fibonacci<11uL>::value' опирается на метапрограмму шаблона, определенную в этой ссылке, и так же эффективен, как и код C 'unsigned long fib11 = 89uL'. Шаблоны оцениваются во время компиляции, давая константу, которая может быть назначена переменной. Таким образом, во время выполнения код фактически идентичен простому присваиванию.

Так что, если это «эквивалентный код C», производительность остается той же. Если эквивалентный код C является «программой, которая может вычислять произвольные числа Фибоначчи, применяемые для поиска 11-го числа в последовательности», то версия C будет намного медленнее, поскольку она должна быть реализована как функция, которая вычисляет значениево время выполнения. Но это «эквивалентный C-код» в том смысле, что это C-программа, которая демонстрирует ту же гибкость (это не просто жестко закодированная константа, а фактическая функция, которая может возвращать любое число в Фибоначчипоследовательность).

Конечно, это не часто полезно. Но это в значительной степени канонический пример шаблонного метапрограммирования.

Более реалистичным примером общего программирования является сортировка.

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

Конечно, альтернативой является рукописныйФункция сортировки, разработанная для вашего конкретного типа данных.

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

struct MyComp {
  bool operator()(const MyType& lhs, const MyType& rhs) {
     // return true if lhs < rhs, however this operation is defined for MyType objects
  }
};

, и это может быть встроено. Функция std::sort передается в качестве аргумента шаблона, поэтому она знает точный тип компаратора, и поэтому она знает, что функция компаратора является не просто указателем неизвестной функции, но MyComp::operator().

КонецВ результате функция C ++ std::sort является точно такой же эффективной, как и ваша кодированная вручную реализация в C того же алгоритма сортировки.

Опять же, если это "эквивалентный код C"», то производительность такая же. Но если «эквивалентный код C» является «обобщенной функцией сортировки, которая может применяться к любому типу и допускает пользовательские компараторы», то универсальная версия программирования на C ++ значительно эффективнее.

Это действительно хитрость. Общее программирование и шаблонное метапрограммирование не "быстрее, чем C". Это методы достижения общего, многократно используемого кода , который так же быстр, как с ручным кодированием, и жестко закодированного C

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

11 голосов
/ 25 июля 2009

Шаблон метапрограммирования (TMP) «запускается» во время компиляции, поэтому он не сравнивает яблоки с яблоками при сравнении их с обычным кодом C / C ++.

Но, если у вас есть что-то, оцененное TMP,тогда нет времени выполнения вообще.

4 голосов
/ 25 июля 2009

Если вы имеете в виду код многократного использования , то да, без сомнения. Метапрограммирование является превосходным способом создания библиотек, а не клиентского кода. Код клиента не является универсальным, он написан для выполнения определенных задач.

Например, посмотрите на qsort из стандартной библиотеки C и стандарт C ++ sort . Вот как работает qsort :

int compare(const void* a, const void* b)
{
    return (*(int*)a > *(int*)b);
}

int main()
{
    int data[5] = {5, 4, 3, 2, 1};

    qsort(data, 5, sizeof(int), compare);
}

Теперь посмотрите на sort :

struct compare
{
    bool operator()(int a, int b)
    { return a < b; }
};

int main()
{
    int data[5] = {5, 4, 3, 2, 1};
    std::sort(data, data+5, compare());
}

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


Еще одно место, где я нахожу метапрограммирование очень красивым, - это когда вы пишете библиотеку, такую ​​как boost :: spirit или boost :: xpressive, с помощью spirit вы можете писать EBNF внутри C ++ ипозвольте компиляции проверить синтаксис EBNF для вас, и с помощью xpressive вы можете написать регулярное выражение и позволить компилятору также проверить синтаксис регулярного выражения!


Я не уверен, что спрашивающийозначает, что TMP вычисляет значения во время компиляции. Это пример, который я написал с использованием boost:)

unsigned long greatestCommonDivisor = boost::math::static_gcd<25657, 54887524>::value;

Что бы вы ни делали с C, вы не можете имитировать приведенный выше код, в основном вы должны вручную вычислить его, а затем присвоить результат greatestCommonDivisor !

1 голос
/ 25 июля 2009

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

ЯИз-за этого опыта я столкнулся с C ++ MetaProgramming.

Я твердо убежден, что лучший код легче читается средним разработчиком. Именно читаемость программного обеспечения является приоритетом № 1. Я могу заставить все работать, используя любой язык ... но умение состоит в том, чтобы сделать его читаемым и легко работоспособным для следующего человека в проекте. Метапрограммирование C ++ не проходит проверку.

1 голос
/ 25 июля 2009

Метапрограммирование шаблонов можно рассматривать как выполнение во время компиляции.

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

Затраты времени выполнения, в которых я не уверен, не должны быть намного больше, чем если бы вы сами написали это на C-коде, как я себе представляю.

1 голос
/ 25 июля 2009

Ответ зависит от этого.

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

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

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

Недостатком является то, что он также дает вам пулемет, чтобы выстрелить себе в ногу.

0 голосов
/ 20 августа 2009

Шаблон метапрограммирования не дает вам никаких магических сил с точки зрения производительности. Это в основном очень сложный препроцессор;вы всегда можете написать эквивалент на C или C ++, это может занять очень много времени.

0 голосов
/ 25 июля 2009

Я не думаю, что есть какая-то шумиха, но ясный и простой ответ о шаблонах дает C ++ FAQ: https://isocpp.org/wiki/faq/templates#overview-templates

Об исходном вопросе: на него нельзя ответить, так как эти вещи не являютсясопоставимый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...