Reputation: 4726
Is there a way to see the compiler-instantiated code for a function template or a class template in C++?
Assume I have the following piece of code:
template <class T> T add(T a, T b) {
return a + b;
}
When I call:
add<int>(10, 2);
... I would like to see the function that the compiler creates for the int
template specialization.
I am using g++, VC++, and need to know the compiler options to achieve this.
Upvotes: 78
Views: 28210
Reputation: 62583
Now there is an on-line tool which does this for you: https://cppinsights.io/ For example, this code
template<class X, class Y> auto add(X x, Y y) {
return x + y;
}
int main()
{
return add(10, 2.5);
}
Is translated to
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));
}
https://cppinsights.io/s/0b914fd3
Upvotes: 29
Reputation: 21
I know this is old, however for modern g++ you can use:
g++ -fdump-tree-*switch* -o array_size array_size.cpp
for switch use all to see all the types that can be used, you'll get about 32 files some are really big. You can use the last component of the file name as the switch to get just that file such as -fdump-tree-gimple
.
This code:
#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;
}
Turns into: 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++ and search for "dump".
Upvotes: 2
Reputation: 4038
Clang (https://clang.llvm.org/) can pretty-print AST of instantiated template:
For your example:
test.cpp
template < class T> T add(T a, T b){
return a+b;
}
void tmp() {
add<int>(10,2);
}
Command to pretty-print AST:
$ clang++ -Xclang -ast-print -fsyntax-only test.cpp
Clang-5.0/Clang 14.0 output:
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);
}
Upvotes: 107
Reputation: 6441
If your looking for the equivalent C++ code then no. The compiler never generates it. It's much faster for the compiler to generate it's intermediate representation straight off than to generate c++ first.
Upvotes: 1
Reputation: 18316
If you want to see the assembly output, use this:
g++ -S file.cpp
If you want to see some (pseudo) C++ code that GCC generates, you can use this:
g++ -fdump-tree-original file.cpp
For your add
function, this will output something like
;; Function T add(const T&, const T&) [with T = int] (null)
;; enabled by -tree-original
return <retval> = (int) *l + (int) *r;
(I passed the parameters by reference to make the output a little more interesting)
Upvotes: 40
Reputation: 6335
You can definitely see the assembly code generated by the g++ using the "-S" option.
I don't think it is possible to display the "C++" equivalent template code - but I would still want a g++ developer to chime in why - I don't know the architecture of gcc.
When using assembly, you can review the resulting code looking for what resembles your function. As a result of running gcc -S -O1 {yourcode.cpp}, I got this (AMD64, gcc 4.4.4)
_Z3addIiET_S0_S0_:
.LFB2:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
leal (%rsi,%rdi), %eax
ret
.cfi_endproc
Which really is just an int addition (leal).
Now, how to decode the c++ name mangler? there is a utility called c++filt, you paste the canonical (C-equivalent) name and you get the demangled c++ equivalent
qdot@nightfly /dev/shm $ c++filt
_Z3addIiET_S0_S0_
int add<int>(int, int)
Upvotes: 23
Reputation: 25581
When the optimizer has done its deeds, you most likely have nothing left that looks like a function call. In your specific example, you'll definitely end up with an inlined addition, at worse. Other than that, you can always emit the generated assembler in a separate file during compilation, and there lies your answer.
Upvotes: 3
Reputation: 25739
The easiest is to inspect the generated assembly. You can get an assembly source by using -S flag for g++.
Upvotes: 2