11

给定一个模板元程序 (TMP),C++ 编译器是否会生成计算实例化类数量的构建统计信息?或者有没有其他方法可以自动获取这个号码?因此,例如无处不在的阶乘

#include <iostream>

template<int N> struct fact { enum { value = N * fact<N-1>::value }; };
template<> struct fact<1> { enum { value = 1 }; };

int main()
{
    const int x = fact<3>::value;
    std::cout << x << "\n";
    return 0;
}

我想取回数字 3(因为 fact<3>、fact<2> 和 fact<1> 已实例化)。这个例子当然是微不足道的,但是当你开始使用例如 Boost.MPL 时,编译时间真的会爆炸,我想知道其中有多少是由于隐藏的类实例化。我的问题主要是针对 Visual C++,但对于 gcc 的答案也将不胜感激。

编辑:我目前对 Visual C++ 非常脆弱的方法是从 Stephan T. Lavavej 的视频/d1reportAllClassLayout 之一添加编译开关并对输出文件进行 grep + 字数统计,但它 (a) 极大地增加了编译时间和 (b)正则表达式很难 100% 正确。

4

3 回答 3

8

我对 GCC 进行了一行更改,使其在实例化每个类模板时打印出它的名称。cc1plus您已经可以在没有标志的情况下直接调用 C++ 前端-quiet来为函数模板获取相同的功能。

我还没有把它变成一个合适的 GCC 选项,这只是我自己的源代码树上的一个 hack。我正在考虑将它作为一个插件来实现,但它不在我的 TODO 列表的顶部。

于 2012-07-09T22:33:01.233 回答
2

当然,没有便携的方法可以做到这一点。

对于大多数编译器来说,有一些 hacky 方法可以做到这一点。您已经为 MSVC 找到了一个。对于 gcc,您可能可以使用 gccxml。或者,对于任何开源编译器(gcc 或 clang),在实例化点添加代码应该非常简单,这些代码要么保持计数,要么记录一些您可以在编译完成后过滤的内容。

对于 Clang/LLVM,您可以构建一个挂钩实例化的插件,这样更简洁,但实际上可能需要更多工作。

带有调试符号、没有优化和剥离的构建最终可能会导致每个实例化的名称混乱,您可以使用 grep 查找。然而,一些编译器(包括 gcc)总是会内联至少一些方法,不管你是否想要它们。如果您愿意修改您的代码,您可能会强制它生成离线实例化,可能是这样的:

template<int N> struct fact { 
  enum { value = N * fact<N-1>::value }; 
  int *dummy() { return &fact<N-1>::value; }
};
于 2012-07-10T00:03:52.243 回答
2

有一个由 Steven Watanabe 编写的工具,可以用来计算模板实例化的数量。你可以在这里得到它。基本上,它会修改代码,以便在每次实例化类时生成编译器警告,然后您可以使用正则表达式处理生成的文本。

于 2012-07-11T12:55:18.577 回答