【问题标题】:Checking whether a class template has been instantiated?检查类模板是否已实例化?
【发布时间】:2015-10-31 15:35:04
【问题描述】:

是否有一种简单的方法可以查看某个类是否已在翻译单元中实例化? C++ Primer 中的一个练习询问每个标记语句,是否发生实例化:

template <typename T> class Stack { };
void f1(Stack<char>); // (a)
class Exercise {
    Stack<double> &rsd; // (b)
    Stack<int> si; // (c)
};
int main() {
    Stack<char> *sc; // (d)
    f1(*sc); // (e)
    int iObj = sizeof(Stack< string >); // (f)
}

我不确定如何才能真正检查我的答案。我想也许我可以为每个类类型使用显式实例化(例如extern template class Stack&lt;char&gt;),然后在程序中永远不会有相应的显式实例化定义。这样,如果某些东西被实例化了,如果定义后来没有出现,那么链接器就会出错。

但是编译器/链接器并不总是能识别出这样的错误:

template <typename T> class A{ };
extern template class A<int>;
int main(){
    A<int> a; 
}

这在 gcc 4.9.2 上编译得很好。但是,如果这是我的程序中唯一的目标文件,那么据我从 N3337 的 [14.7.2][11] 可以看出,这应该是一个错误:

如果一个实体是同一翻译单元中的显式实例化声明和显式实例化定义的主体,则定义应遵循声明。作为主体的实体 一个显式的实例化声明,并且它的使用方式也会导致翻译单元中的隐式实例化(14.7.1)应该是程序中某处显式实例化定义的主题;否则程序格式错误,不需要诊断。

(我猜“不需要诊断”是为什么这不会引发错误?)。或者,当不完整的类类型对表达式不可行时,实例化就会发生 - 这样我就可以通过删除 Stack 的定义来检查?

template <typename T> class Stack;

所以每个不完整的类型错误都对应一个实例化的地方?

【问题讨论】:

  • 仅仅删除Stack 的定义对于任意情况是不够的,因为某些规则可以同时使用完整的类类型和不完整的类类型。如果他们有一个完整的班级类型,他们只是碰巧收集了更多信息。例如,ADL 和运算符函数查找。不过,在 sizeof 这样的情况下,这应该足够了。
  • template&lt;class&gt; struct always_false : std::false_type {};,然后是 static_assert(always_false&lt;T&gt;::value, "If this fires, 'Stack' is instantiated");Stack 的定义中。
  • @T.C.但是,这与“检查”有什么关系?那会产生硬错误吗? (没看问题,只看标题)
  • @Columbo 因为OP的实际问题是“弄清楚这个语句是否会导致隐式实例化”?
  • @T.C.但是在单个诊断消息/格式错误之后,该标准不再提出任何要求。所以他不能在一个程序中检查不止一次,这样:p

标签: c++ templates c++11 instantiation


【解决方案1】:

您可以在可执行文件上使用 nm 工具。这将显示包含函数定义的文件。 gcc 还提供了一个标志,用于在进行链接时去除未使用的函数。

编译时使用“-fdata-sections”将数据保存在单独的数据部分中,使用“-ffunction-sections”将函数保存在单独的部分中,因此如果未使用它们(数据和函数)可以丢弃。 与“--gc-sections”链接以删除未使用的部分。

【讨论】:

    猜你喜欢
    • 2018-10-21
    • 1970-01-01
    • 2014-03-30
    • 1970-01-01
    • 2014-04-30
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多