2014-10-15 3 views
3

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

По существу у меня есть библиотека полезных математических функций, предназначенных для работы с примитивами, такими как Vector3, Vector4, Quaternion и т. Д. Все они предназначены для использования с аргументом шаблона, который является float или double (а в некоторых случаях int).

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

template<typename T> 
Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b) 
{ do something... } 

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

Заголовки становятся довольно большими, хотя время сборки увеличивается, и его трудно найти существование функций, просто взглянув на заголовки (это одна из многих причин, по которой мне нравится разделять объявление от реализаций).

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

//in .h 
    template<typename T> 
    Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b) 
    { do something... } 

    //in .cpp 
    template Vector3<float> foo<float>(const Vector4<float>& a, 
            const Quaternion<float>& b); 
    template Vector3<double> foo<double>(const Vector4<double>& a, 
             const Quaternion<double>& b); 

Это должно помочь со временем компиляции? Это повлияет на возможность возможности встроенных функций? Являются ли ответы на любой из этих вопросов, как правило, конкретным компилятором?

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

Кроме того, я мог бы сделать это:

//in .h 
    template<typename T> 
    Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b); 

    //in .cpp 
    template<typename T> 
    Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b) 
    { do something... } 

    template Vector3<float> foo<float>(const Vector4<float>& a, 
            const Quaternion<float>& b); 
    template Vector3<double> foo<double>(const Vector4<double>& a, 
             const Quaternion<double>& b); 

Те же вопросы для этого метода:

Это должно помочь со временем компиляции? Это повлияет на возможность возможности встроенных функций? Являются ли ответы на любой из этих вопросов, как правило, конкретным компилятором?

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

Приятно, что ему удается отделить объявление и определение шаблонных функций (для конкретных аргументов шаблона), не прибегая к использованию чего-то вроде использования .inl, включенного в нижней части файла .h. Это также скрывает реализацию от пользователя библиотеки, которая является полезной (но еще не совсем необходимой), но при этом все еще можно использовать шаблоны, поэтому мне не нужно выполнять функцию N раз.

Есть ли способ разрешить встраивание путем настройки метода?

Мне было сложно просто поработать в поисках ответа на эти вопросы, и стандартная спецификация трудно понять по этим темам (по крайней мере для меня).

BTW, ожидается, что он будет скомпилирован с VS2010, VS2012 и GCC 4.7.

Любая помощь будет оценена по достоинству.

Благодаря

+0

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

+1

@MatsPetersson: Это самое загадочное заявление, которое я слышал весь день. –

+0

@MatsPetersson Это не так, обычные компиляторы не имеют понятия «файл заголовка». После того, как вы '# include' заголовочный файл в файле cpp, это как если бы заголовочный файл был частью файла cpp. Вероятно, вы имеете в виду, что определение метода/класса шаблона должно быть доступно в текущем блоке перевода, если оно создается для типа, который не создается в каких-либо других единицах перевода (файлы объектов, которые он получит связанный с). Но если вы явно создаете экземпляры в одном для всех типов, которые вам нужны (как OP), вам нужны только объявления в файлах заголовков. – Oguk

ответ

2

Я принимаю вашу технику, предназначенную сделать то же самое, как и ответ на этот вопрос: Template instantiation effect on compile duration

Чтобы достичь желаемого результата, вам также необходимо, чтобы предотвратить автоматическое создание экземпляра, объявив явное экземпляров в заголовке с использованием extern. См Explicit instantiation declaration with extern

//in .h 
template<typename T> 
Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b); 

extern template Vector3<float> foo<float>(const Vector4<float>& a, 
              const Quaternion<float>& b); 

extern template Vector3<double> foo<double>(const Vector4<double>& a, 
              const Quaternion<double>& b); 

//in .cpp 
template<typename T> 
Vector3<T> foo(const Vector4<T>& a, 
       const Quaternion<T>& b) 
{ /* do something...*/ } 

template Vector3<float> foo<float>(const Vector4<float>& a, 
            const Quaternion<float>& b); 
template Vector3<double> foo<double>(const Vector4<double>& a, 
            const Quaternion<double>& b); 

Это должно помочь со временем компиляции? Это повлияет на возможность возможности включения функций? Являются ли ответы на любой из этих вопросов в целом конкретным компилятором?

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

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

Стандарт C++ неявно позволяет компилятору выполнять экземпляр каждой уникальной специализированной специализации только один раз для всех единиц перевода. То есть, экземпляр функций шаблона может быть отложен и выполнен после начальной компиляции, как описано в документации Comeau. Независимо от того, была ли эта оптимизация реализована или нет, зависит от компилятора, но, конечно же, не реализована ни в одной версии MSVC до 2015 года.

Если ваш компилятор выполняет экземпляр при времени ссылки, этот метод предотвратит встраивание, если компилятор не выполнит поддержка кросс-модуля. Более поздние версии MSVC, GCC и Clang поддерживают кросс-модульную вставку во время соединения с дополнительным компоновщиком (LTCG или LTO). См. Can the linker inline functions?

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