13

Допустим, у меня есть следующий metafunction:Оптимизация производительности во время компиляции с помощью кэширования метафункции

template <typename T> 
struct make_pair { 
    using type = std::pair< 
     typename std::remove_reference<T>::type, 
     typename std::remove_reference<T>::type 
    >; 
}; 

Будет ли это улучшить скорость компиляции, чтобы сделать это (или что-то еще) вместо?

template <typename T> 
struct make_pair { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = std::pair<without_reference, without_reference>; 
}; 

Я вижу две возможности:

  1. Компилятор должен сделать некоторую работу каждый раз, когда он видит typename std::remove_reference<T>::type. Использование промежуточного псевдонима имеет какое-то «кэширование» поведения, которое позволяет компилятору выполнять некоторую работу только один раз.

  2. Измерение времени компиляции измеряется с точки зрения количества экземпляров шаблонов, которые должен выполнять компилятор. Поскольку std::remove_reference<T>::type относится к тому же типу, что и std::remove_reference<T>::type, в обоих случаях требуется только один экземпляр шаблона, поэтому обе реализации эквивалентны производительности времени компиляции WRT.

Я думаю, что В является правильным, но я хотел бы быть уверен. Если ответ окажется специфичным для компилятора, мне бы в основном было интересно узнать ответ для Clang и GCC.

Edit:

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

template <typename ...> struct result;  

template <typename T> 
struct with_cache { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = result<without_reference, ..., without_reference>; 
}; 

template <typename T> 
struct without_cache { 
    using type = result< 
     typename std::remove_reference<T>::type, 
     ..., 
     typename std::remove_reference<T>::type 
    >; 
{ }; 

using Result = with[out]_cache<int>::type; 

Это среднее время для 10 компиляций программы, с 10 000 параметров шаблона в result<>.

   ------------------------- 
       | g++ 4.8 | clang++ 3.2 | 
----------------------------------------- 
| with cache | 0.1628s | 0.3036s  | 
----------------------------------------- 
| without cache | 0.1573s | 0.3785s  | 
----------------------------------------- 

Тестовая программа генерируется по имеющимся скриптам here.

+4

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

+0

Я видел разговор о clang, который говорит, что они делают hashtables для экземпляров шаблонов вместо связанных списков. Я не знаю, с кем они сравнивались. –

+0

Компилятор 'template', который не выполняет memoization, будет смехотворно медленным. – Yakk

ответ

2

Я не могу сказать, что это относится ко всем компиляторам, но GCC и, скорее всего, любой другой главный компилятор, собирается использовать memoization. Если вы думаете об этом, это почти необходимо.

Рассмотрим следующий код

&f<X, Y>::some_value == &f<X, Y>::some_value 

Это необходимо, чтобы быть правдой, так что компилятор должен убедиться, что он не дублирует определения методов и статических членов. Теперь могут быть другие способы сделать это, но это просто кричит мне воспоминания; Я не вижу другого способа реализовать это даже (предоставлено, я думал об этом очень сложно)

Когда я использую TMP, я ожидаю, что произойдет мемонирование. Это было бы настоящей болью, если бы это было не так, слишком медленно. Единственный способ, с помощью которого я видел существенные различия во времени выполнения компиляции, - это: а) использование более быстрого компилятора, такого как Clang (что примерно в 3 раза быстрее, чем GCC) и выбора разных алгоритмов. Небольшие постоянные факторы кажутся мне еще менее значимыми в TMP, чем у C или C++. Выбирайте правильный алгоритм, старайтесь не делать ненужной работы, старайтесь сохранить количество экземпляров и использовать хороший компилятор (MSVC++ действительно медленный и далекий от соответствия C++ 11, но GCC и Clang неплохие); это все, что вы можете сделать на самом деле.

Кроме того, вы должны всегда жертвовать временем компиляции для лучшего кода. Преждевременная оптимизация времени компиляции - это скорее зло, чем обычная преждевременная оптимизация. Это может быть исключение, если по какой-то причине производительность становится массово непозволительной для развития; Однако я никогда не слышал о таком случае.

+1

Этот ответ неплохой, но на самом деле это не то, что я искал. Я ищу что-то более определенное, как подтверждение от разработчика GCC или Clang. Кроме того, причина, по которой я задавала этот вопрос, заключается в том, что я работал над метапрограммирующими библиотеками и оптимизировал время компиляции. –

Смежные вопросы