Скомпилируйте сложный шаблон только один раз в проекте [duplicate]

Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));

Даже для этой цели,

Map<String,Choice> map=  list1.stream().collect(()-> new HashMap<String,Choice>(), 
            (r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));
87
задан Community 30 March 2016 в 13:51
поделиться

4 ответа

Вы должны использовать extern template, чтобы заставить компилятор not создать экземпляр шаблона, когда вы знаете , что он будет создан в другом месте. Он используется для уменьшения времени компиляции и размера объектного файла.

Например:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}

// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}

// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

Это приведет к следующим объектным файлам:

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

Если оба файла связаны друг с другом, один void ReallyBigFunction<int>() будет отброшен, что приведет к потерянному времени компиляции и размерному размеру объекта.

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

Изменение source2.cpp на:

// source2.cpp

#include "header.h"
extern template void ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

В результате будут созданы следующие объектные файлы:

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

Когда оба из них будут связаны друг с другом, второй объектный файл будет просто использовать символ из первого объектного файла. Нет необходимости отбрасывать и не тратить время на компиляцию и размер объектного файла.

Это должно использоваться только в проекте, например, когда вы используете шаблон типа vector<int> несколько раз, вы должны использовать extern во всех, кроме одного исходного файла.

Это также относится к классам и функциям как одна, так и даже функции членов шаблона.

140
ответ дан user1902689 24 August 2018 в 06:28
поделиться

В Википедии есть лучшее описание

В C ++ 03 компилятор должен создавать экземпляр шаблона всякий раз, когда в блоке трансляции встречается полностью заданный шаблон. Если шаблон создается с одинаковыми типами во многих единицах перевода, это может значительно увеличить время компиляции. Невозможно предотвратить это в C ++ 03, поэтому C ++ 11 представил объявления extern-шаблонов, аналогичные объявлениям extern-данных.

C ++ 03 имеет этот синтаксис, чтобы заставить компилятор создать экземпляр template:

  template class std::vector<MyClass>;

C ++ 11 теперь предоставляет этот синтаксис:

  extern template class std::vector<MyClass>;

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

< / blockquote>

Предупреждение: nonstandard extension used...

Microsoft VC ++ уже несколько лет использует нестандартную версию этой функции (в C ++ 03) , Компилятор предупреждает об этом, чтобы предотвратить проблемы с переносимостью с кодом, который необходим для компиляции на разных компиляторах.

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

38
ответ дан akim 24 August 2018 в 06:28
поделиться

Известная проблема с шаблонами - это раздувание кода, что является следствием генерации определения класса в каждом модуле, который вызывает специализацию шаблона класса. Чтобы предотвратить это, начиная с C ++ 0x, перед спецификацией шаблона класса

#include <MyClass> extern class CMyClass<int>;

можно использовать ключевое слово extern . Явное инкрементирование класса шаблона должно происходить только в одной единице перевода, предпочтительнее вариант с определением шаблона (MyClass.cpp)

template class CMyClass<int>;
template class CMyClass<float>;
4
ответ дан damirlj 24 August 2018 в 06:28
поделиться

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

0
ответ дан qqqqq 24 August 2018 в 06:28
поделиться
Другие вопросы по тегам:

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