我们能看到C++编译器实例化的模板吗?

问题描述 投票:0回答:9

有没有办法查看 C++ 中函数模板或类模板的编译器实例化代码?

假设我有以下代码:

template <class T> T add(T a, T b) {
    return a + b;
}

当我打电话时:

add<int>(10, 2); 

...我想查看编译器为

int
模板专业化创建的函数。

我正在使用 g++、VC++,并且需要了解编译器选项来实现此目的。

c++ templates gcc compiler-flags
9个回答
99
投票

Clang (https://clang.llvm.org/) 可以漂亮地打印实例化模板的 AST:

举个例子:

测试.cpp

template < class T> T add(T a, T b){
    return a+b;
}

void tmp() {
    add<int>(10,2); 
}

漂亮打印 AST 的命令:

$ clang++ -Xclang -ast-print -fsyntax-only test.cpp

Clang-5.0/Clang 14.0 输出:

template <class T> T add(T a, T b) {
    return a + b;
}
template<> int add<int>(int a, int b) {
    return a + b;
}
void tmp() {
    add<int>(10, 2);
}

40
投票

如果您想查看汇编输出,请使用以下命令:

g++ -S file.cpp

如果你想查看 GCC 生成的一些(伪)C++ 代码,你可以使用这个:

g++ -fdump-tree-original file.cpp

对于您的

add
函数,这将输出类似

;; Function T add(const T&, const T&) [with T = int] (null)
;; enabled by -tree-original

return <retval> = (int) *l + (int) *r;

(我通过引用传递参数以使输出更有趣)


24
投票

现在有一个在线工具可以为您执行此操作:https://cppinsights.io/例如,此代码

template<class X, class Y> auto add(X x, Y y) {
  return x + y;
}

int main()
{
  return add(10, 2.5);
}

翻译为

template<class X, class Y> auto add(X x, Y y) {
  return x + y;
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
double add<int, double>(int x, double y)
{
  return static_cast<double>(x) + y;
}
#endif


int main()
{
  return static_cast<int>(add(10, 2.5));
}

23
投票

您绝对可以使用“-S”选项看到g++生成的汇编代码。

我认为不可能显示“C++”等效模板代码 - 但我仍然希望 g++ 开发人员补充原因 - 我不知道 gcc 的体系结构。

使用汇编时,您可以查看生成的代码,查找与您的函数相似的代码。运行 gcc -S -O1 {yourcode.cpp} 的结果是,我得到了这个(AMD64,gcc 4.4.4)

_Z3addIiET_S0_S0_:
.LFB2:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    leal    (%rsi,%rdi), %eax
    ret
    .cfi_endproc

这实际上只是一个 int 加法(leal)。

现在,如何解码 C++ 名称修饰器?有一个名为 c++filt 的实用程序,您粘贴规范(C 等效)名称,您将获得分解后的 C++ 等效名称

qdot@nightfly /dev/shm $ c++filt 
_Z3addIiET_S0_S0_ 
int add<int>(int, int)

3
投票

当优化器完成其工作后,您很可能没有留下任何看起来像函数调用的东西。在您的具体示例中,最糟糕的是,您肯定会得到内联添加。除此之外,您始终可以在编译期间在单独的文件中发出生成的汇编程序,这就是您的答案。


2
投票

最简单的是检查生成的程序集。您可以通过使用 g++ 的 -S 标志来获取汇编源代码。


2
投票

我认为 c++ Insights 就是你想要的。


1
投票

如果您正在寻找等效的 C++ 代码,那么没有。编译器永远不会生成它。编译器直接生成中间表示比首先生成 C++ 要快得多。


0
投票

我知道这已经很旧了,但是对于现代 g++ 你可以使用:

g++ -fdump-tree-*switch* -o array_size array_size.cpp

对于 switch 使用 all 查看所有可以使用的类型,您将得到大约 32 个文件,其中一些文件非常大。您可以使用文件名的最后一个部分作为 switch 来获取该文件,例如

-fdump-tree-gimple

此代码:

#include <iostream>

template <typename T, size_t N>
size_t ARRAYSIZET(T (&a)[N])
{
    return N;
}

int main (int argc, char * argv[])
{
    int a[] = {1,2,3,4,5,6};
    std::cout << ARRAYSIZET(a) << std::endl;
}

变成: g++ -fdump-tree-gimple -o array_size array_size.cpp

int main (int argc, char * * argv)
{
  int D.53868;

  {
    int a[6];
    try
      {
        a[0] = 1;
        a[1] = 2;
        a[2] = 3;
        a[3] = 4;
        a[4] = 5;
        a[5] = 6;
        _1 = std::basic_ostream<char>::operator<< (&cout, 6);
        std::basic_ostream<char>::operator<< (_1, endl);
        _2 = ARRAYSIZET<int, 6> (&a);
        _3 = std::basic_ostream<char>::operator<< (&cout, _2);
        std::basic_ostream<char>::operator<< (_3, endl);
      }
    finally
      {
        a = {CLOBBER(eol)};
      }
  }
  D.53868 = 0;
  return D.53868;
}

size_t ARRAYSIZET<int, 6> (int[6] & a)
{
  size_t D.53874;

  D.53874 = 6;
  return D.53874;
}

man g++ 并搜索“dump”。

© www.soinside.com 2019 - 2024. All rights reserved.