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

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

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

Мои вопросы:

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

Ответ 1

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

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

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

Подробную информацию см. на gnu для полной информации

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

Ответ 2

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

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

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

http://www.freeimagehosting.net/uploads/a2e6f1dc27.png

Ниже приведены некоторые быстрые результаты производительности для создания шаблонов в Clang и GCC 4.2. Тест очень прост: измерьте время компиляции (-fsyntax-only) для единицы перевода, которая вычисляет число N-й Фибоначчи с помощью метапрограммы шаблона. Кажется, что Clang масштабируется линейно (или близко к нему) с количеством экземпляров. И, хотя вы не можете увидеть его на диаграмме, Clang чуть больше 2x быстрее, чем GCC в начале (Fibonacci<100>).

CLang все еще находится в начале дня, но я думаю, что у него есть хорошие шансы стать отличным компилятором на С++.

Ответ 3

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

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

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

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

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

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

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), динамически типизируются, но это можно сделать со статическим набором. Однако это вряд ли когда-либо будет тем, что вы увидите на С++.

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

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

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

  • Построить граф зависимостей для начальных значений значения размера "size"
  • Построить тип шаблона для каждого ребра в графе
  • Привязать все символы, на которые ссылается каждый построенный тип шаблона
  • Топологически сортировать граф зависимостей
  • Пройдите график и оцените константы

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

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

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

Ответ 4

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

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

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

Если это ваша проблема, посмотрите здесь, по соответствующему вопросу:

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

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

Он использует флаг g++ -fno-implicit-templates.

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

Ответ 5

Это не тот ответ, который вам нужен, но Уолтер Брайт был основным разработчиком первого собственного компилятора С++ и оптимизированного С++ complier. В конце концов, он написал свой собственный язык программирования под названием D. Это в основном улучшение на С++ и лучше справляется с шаблонами.

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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