我使用的是图书馆,它是一个只用于3D图形的数学实用程序的头级集合。通过在Clang和ClangBuildAnalyzer上使用ClangBuildAnalyzer,我注意到大量时间用于实例化glm类型:
**** Templates that took longest to instantiate:
16872 ms: glm::vec<4, signed char, glm::packed_highp> (78 times, avg 216 ms)
15675 ms: glm::vec<4, unsigned char, glm::packed_highp> (78 times, avg 200 ms)
15578 ms: glm::vec<4, float, glm::packed_highp> (78 times, avg 199 ms)
...因此,我决定为glm创建一个包装头/源对,并使用extern template来避免不必要的实例化:
// glmwrapper.h
#pragma once
#include <glm.hpp>
extern template struct glm::vec<4, signed char, glm::packed_highp>;
extern template struct glm::vec<4, unsigned char, glm::packed_highp>;
extern template struct glm::vec<4, float, glm::packed_highp>;// glmwrapper.cpp
template struct glm::vec<4, signed char, glm::packed_highp>;
template struct glm::vec<4, unsigned char, glm::packed_highp>;
template struct glm::vec<4, float, glm::packed_highp>;现在,在我的项目中,我不包括<glm.hpp>,而是"glmwrapper.h"。不幸的是,这并没有改变任何事情。使用-ftime-trace和ClangBuildAnalyzer再次报告相同数量的实例化。也没有可测量的编译时间差。
我怀疑这是因为#include <glm.hpp>实际上最终包含了模板定义,而随后的extern template声明只是多余的。
在不修改glm 库的情况下,有没有办法实现我想要的?
在伪码中,我想要这样的东西:
// glmwrapper.h (psuedocode)
#pragma once
#include <glm.hpp>
// Make definition of the templates unavailable:
undefine template struct glm::vec<4, signed char, glm::packed_highp>;
undefine template struct glm::vec<4, unsigned char, glm::packed_highp>;
undefine template struct glm::vec<4, float, glm::packed_highp>;
// Make declaration of the templates available:
extern template struct glm::vec<4, signed char, glm::packed_highp>;
extern template struct glm::vec<4, unsigned char, glm::packed_highp>;
extern template struct glm::vec<4, float, glm::packed_highp>;// glmwrapper.cpp (psuedocode)
// Define templates only in the `.cpp`, not in the header:
template struct glm::vec<4, signed char, glm::packed_highp>;
template struct glm::vec<4, unsigned char, glm::packed_highp>;
template struct glm::vec<4, float, glm::packed_highp>;发布于 2020-05-13 03:41:51
不幸的是,没有办法避免这些实例化。类模板的显式实例化声明不会阻止对该模板进行(隐式)实例化;它只是防止实例化它的非内联、非模板成员函数(通常都不是!)因为其他的翻译单元会提供实际的功能符号和目标代码。
并不是看到模板定义会导致实例化(哪些专门化将被实例化?)。原因是要求类完成的代码仍然需要知道它的布局和成员函数声明(为了过载解决),而且一般来说,除了实例化类之外,没有其他方法可以知道:
template<class T> struct A : T::B {
typename std::conditional<sizeof(T)<8,long,short>::type first;
typename T::X second;
A() noexcept(T::y)=default; // perhaps deleted
using T::B::foo;
void foo(T);
// and so on…
};
void f() {A<C> a; a.foo(a.first);} // …maybe?这种“透明性”也扩展到模板实体的其他几种:如果编译需要模板的定义,为链接器生成的符号是无关的。
好消息是,C++20的模块应该有助于解决这样的情况:模块接口中的显式实例化定义将导致典型的实现将实例化类定义与其余模块接口数据一起缓存,从而避免在导入转换单元时进行解析和实例化。模块还删除类中定义的类成员和朋友的隐式inline (这在很长一段时间内都没有多大意义),增加了函数的数量(或者,换句话说,方便性),对于这些函数,显式实例化声明确实阻止了隐式实例化。
https://stackoverflow.com/questions/61477486
复制相似问题