首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在只有第三方头的库中使用“`extern”

在只有第三方头的库中使用“`extern”
EN

Stack Overflow用户
提问于 2020-04-28 09:58:33
回答 1查看 759关注 0票数 10

我使用的是图书馆,它是一个只用于3D图形的数学实用程序的头级集合。通过在Clang和ClangBuildAnalyzer上使用ClangBuildAnalyzer,我注意到大量时间用于实例化glm类型:

代码语言:javascript
复制
**** 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来避免不必要的实例化:

代码语言:javascript
复制
// 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>;
代码语言:javascript
复制
// 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-traceClangBuildAnalyzer再次报告相同数量的实例化。也没有可测量的编译时间差。

我怀疑这是因为#include <glm.hpp>实际上最终包含了模板定义,而随后的extern template声明只是多余的。

在不修改glm 库的情况下,有没有办法实现我想要的?

在伪码中,我想要这样的东西:

代码语言:javascript
复制
// 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>;
代码语言:javascript
复制
// 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>;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-13 03:41:51

不幸的是,没有办法避免这些实例化。类模板的显式实例化声明不会阻止对该模板进行(隐式)实例化;它只是防止实例化它的非内联、非模板成员函数(通常都不是!)因为其他的翻译单元会提供实际的功能符号和目标代码。

并不是看到模板定义会导致实例化(哪些专门化将被实例化?)。原因是要求类完成的代码仍然需要知道它的布局和成员函数声明(为了过载解决),而且一般来说,除了实例化类之外,没有其他方法可以知道:

代码语言:javascript
复制
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 (这在很长一段时间内都没有多大意义),增加了函数的数量(或者,换句话说,方便性),对于这些函数,显式实例化声明确实阻止了隐式实例化。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61477486

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档