Существуют ли оптимизированные компиляторы c ++ для использования в шаблонах? - PullRequest
22 голосов
/ 24 февраля 2009

C ++ шаблоны были благословением в моей повседневной работе благодаря своей мощи. Но нельзя игнорировать (очень, очень, очень долгое) время компиляции, которое является результатом интенсивного использования шаблонов (привет метапрограммирование и библиотеки Boost). Я прочитал и попробовал довольно много возможностей для ручной реорганизации и изменения кода шаблона, чтобы сделать его максимально быстрым.

Теперь мне интересно, существуют ли какие-либо компиляторы c ++, которые пытаются минимизировать необходимое время для интерпретации шаблонных классов. Я могу ошибаться, но я чувствую, что компиляторы, которых я знаю, только добавили интерпретацию шаблона к своим предыдущим версиям.

Мои вопросы:

  • Неужели код шаблона с ++ так сложно интерпретировать, что оптимизировать особо нечего? (я очень сомневаюсь в этом)
  • Существуют ли компиляторы c ++, которые действительно оптимизируют интерпретацию "шаблонов c ++"?
  • Существуют ли проекты для разработки нового поколения компиляторов c ++, которые бы оптимизировали это?
  • Если бы вы приняли участие в таком проекте, какими были бы ваши рекомендации?

Ответы [ 8 ]

14 голосов
/ 25 февраля 2009

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

Существуют ли проекты для разработки нового поколения компиляторов c ++, которые бы оптимизировали это?

Да, существует CLang , который является интерфейсом языка C для инфраструктуры компилятора LLVM. И CLang, и LLVM кодируются с использованием C ++. Среди разработчиков CLang Дуглас Грегор, автор нескольких предложений по языку C ++ 1x, таких как шаблоны с переменным числом аргументов и концепции. Для справки см. Этот тест Дугласа Грегора из Clang против GCC

image

Here are some quick-n-dirty performance results for template instantiation in Clang and GCC 4.2. The test is very simple: measure compilation time (-fsyntax-only) for a translation unit that computes the Nth Fibonacci number via a template metaprogram. Clang appears to be scaling linearly (or close to it) with the number of instantiations. And, although you can't see it in the chart, Clang is a little over 2x faster than GCC at the beginning (Fibonacci<100>).

CLang is still in its первые дни но я думаю, что у него есть хорошие шансы стать отличным компилятором C ++.

9 голосов
/ 25 февраля 2009

Это действительно не ответ на ваш вопрос. Это скорее побочное наблюдение.

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

Но грубая идея должна быть правильной.

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

Они не указаны напрямую как код, который вы хотите, чтобы компилятор запускал во время компиляции. Возьмите пример вычисления длины списка типов.

Если бы вы могли написать код, подобный этому:

compile_time size_t GetLength(TypeList * pTypeList)
{
    return DoGetLength(pTypeList, 0);
}

compile_time size_t DoGetLength(TypeList * pTypeList, size_t currentLength)
{
    if (pTypeList)
    {
        return DoGetLength(pTypeList->Next, ++currentLength);
    }
    else
    {
         return currentLength;
    }
}

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

Это был бы простой рекурсивный вызов функции.

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

Однако проблема в C ++ состоит в том, что код написан так:

template <typename First,  typename Second>
struct TypeList
{
    typedef First Head;
    typedef Second Tail;
};

template <>
struct ListSize<NullType>
{
    enum {  size = 0  };
};

template <typename Head, typename Tail>
struct ListSize<TypeList<Head, Tail> >
{
    enum {  size = 1 + ListSize<Tail>::size  };
};

Чтобы компилятор "выполнил" метапрограмму, он должен:

  1. Построить граф зависимостей для начальных значений значения перечисления "size"
  2. Построить тип шаблона для каждого ребра на графике
  3. Свяжите все символы, на которые ссылается каждый тип созданного шаблона
  4. Топологически отсортировать граф зависимостей
  5. Пройдите по графику и оцените константы

Это намного дороже, чем просто запуск O (N) рекурсивного алгоритма.

Наихудшим случаем будет что-то вроде O (N * M * L), где N равно длине списка, M - это уровень вложенности области, а L - количество символов в каждой области.

Мой совет - минимизировать количество используемого вами метапрограммирования на С ++.

7 голосов
/ 25 февраля 2009

Основная проблема с шаблонами следующая:

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

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

Если это ваша проблема, тогда посмотрите здесь, на связанный вопрос:

Он получил очень хороший ответ , который решает эту проблему .

По сути, это включает в себя создание шаблонов, которые вам нужны, и компиляцию их в объектный файл. Позже вы можете ссылаться на него, и вам не нужно включать этот код везде. Он разделен на скомпилированный объектный файл. Примечание. Это имеет смысл только в том случае, если вы используете только несколько созданных экземпляров типов шаблонов (скажем, вам нужно только MyType<int> и MyType<double> в вашей программе).

Используется флаг g++ -fno-implicit-templates.

Эта техника настолько полезна, что я думаю, что она должна быть включена в faq C ++: [35.12] Почему я не могу отделить определение своего класса шаблонов от его объявления и поместить его в файл .cpp?

4 голосов
/ 19 апреля 2010

Кажется, что g ++ 4.5 добился огромного прогресса в работе с шаблонами. Вот два неизбежных изменения.

  • "При печати имени специализации шаблона класса G ++ теперь будет пропускать любые аргументы шаблона, которые приходят из аргументов шаблона по умолчанию." Это можно считать незначительной модификацией, но это окажет огромное влияние на разработку с помощью шаблонов c ++ (когда-либо слышали о нечитаемых сообщениях об ошибках ...? Не более!)

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

См. На сайте GNU для получения полной информации

На самом деле, мне уже интересно, есть ли еще проблемы с шаблонами c ++! Ммм, да, есть, но сейчас давайте сосредоточимся на яркой стороне!

2 голосов
/ 31 июля 2009

Золотой компоновщик может помочь сократить время соединения примерно в 5 раз, что может сократить общее время компиляции. Это особенно полезно, поскольку компоновка не может быть распараллелена так же, как компиляция.

(Не прямой ответ, но, надеюсь, это полезно).

2 голосов
/ 24 февраля 2009

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

Я не знаю ни одного компилятора c ++, который был бы оптимизирован для использования в шаблонах.

1 голос
/ 24 февраля 2009

Попробуйте Incredibuild . Это значительно сокращает время компиляции / сборки.

Этот продукт в основном позволяет Visual C ++ создавать на нескольких машинах в вашей организации, используя преимущества циклов простоя. Я использовал Incredibuild для огромных проектов (500 клок) с большим количеством шаблонов кода и получил хорошее ускорение во время сборки.

0 голосов
/ 24 февраля 2009

Я думаю, что сами шаблоны не так сложны сами по себе. Мы увидим, когда концепции будут введены в c ++ 0x и т. Д., Но на данный момент шаблоны просто (почти) как макросы, поэтому реальная проблема не в том, если вы оптимизировали компиляторы c ++ для шаблонов. Проблема в том, что шаблоны генерируют такой огромный объем кода при компиляции, что замедляют компиляцию.

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