Debugging Template Instantiations

Debugging template instantiations

These are pretty basic, but they have worked for me in most cases. I'm interested to see what others have to say too.

Apologies for the contrived examples.

Use sandboxes

Starting with small sandboxes to test template code as soon as it starts behaving weird or you are doing something complicated. I am pretty comfortable with templates and I still do this almost immediately. Simply, it uncovers errors faster. You have done it for us here, so I presume that this is moot.

Specify temporary types

Temporaries can obfuscate where your intentions are not met. I have seen a lot of code that does something like the below.

template<typename T>
T calc(const T &val) {
return some_other_calc(val) / 100.0;
}

Telling the compiler what type you expect will fail faster and potentially will give you a better message to deal with.

template<typename T>
T calc(const T &val) {
T val_ = some_other_calc(val);
return val_ / 100.0;
}

Use typeid

Using typeid(T).name() to print template names in debug statements. This will give you a string that you can use to see how the compiler decided to fulfill the type.

template<typename T>
typename void test() {
std::cout << "testing type " << typeid(T).name() << std::endl;
// ...
}

Avoid unnecessary default implementations

Write templates in such a way that they don't have default implementations.

template<typename T, bool is_integral = boost::is_numeric<T>::value >
struct my_traits;

template<typename T>
struct my_traits<T, true> {
typedef uint32_t cast_type;
};

template<typename T>
void print_whole_number(T &val) {
std::cout << static_cast<my_traits<T>::cast_type>(val) << std::endl;
}

This enforces users of print_whole_number have their own my_traits specialization. They will get an compiler error instead of half working because you couldn't supply a good implementation for all types. The compiler error won't be immediately helpful if used in a disparate part of a code base, admittedly.

How do you debug heavily templated code in c++?

For the STL at least there are tools available that will output more human-friendly error messages. See http://www.bdsoft.com/tools/stlfilt.html

For non-STL templates you'll just have to learn what the errors mean. After you've seen them a dozen times it becomes easier to guess what the problem is. If you post them here maybe somebody can help you figure it out.

inspect C++ template instantiation

With templates we simply don't have clean output facilities and there are no compilers i know of that allow you to directly view template instantiations. The closest i found regarding metaprogram debugging was a paper on Templight.

For now the best utilities seem to be:

  • static asserts & concept checks (clearly assert your assumptions)
  • the mentioned instantiation backtraces (e.g. by using static asserts)
  • letting instantiations generate warnings (boost::mpl::print might do it)
  • a tracer, a custom class that gets passed as a template argument and is used to emit runtime output (introduced by C++ Templates - The Complete Guide)

How to debug template arguments at compile-time?

I believe you're using MSVC++, if so, then see the output window, it might have more info printed, especially the line number along with the filename. Once you know the file and line number, you can start from there.

Output window usually prints everything, like how and with what template argument(s), a template is instantiated. Everything step by step. Those messages are very useful when debugging.

As you found yourself, enabling /WL prints more detail messages in the output window.

How to debug and print a template alias type c++

A quick and dirty way:

template <typename T>
void print_type()
{
#ifndef _MSC_VER
std::cout << __PRETTY_FUNCTION__ << '\n';
#else
std::cout << __FUNCSIG__ << '\n';
#endif
}

What exactly is printed depends on the compiler. For print_type<int>();, my Clang prints void print_type() [T = int].

See this thread for removing anything other than the type name from such strings.

Can I add a breakpoint only for a specific template instantiation?

I found it.

Just put a breakpoint in the line you want (I'll show an example with std::shared_ptr<>).

Then go to the Breakpoints window and notice that when it breaks, there's a little + next to the breakpoint that will open all the different instantiations.

The line in bold is the breakpoint that is currently active.

Breakpoint on a templated function

Now, unfortunately, the Breakpoints window doesn't show you the actual template instantiation.

But, you can use the call stack to see which instantiation is currently used.
Or, you can right click on each of the breakpoints, and choose "Go To Disassembly".

This may give you a hint as to the actual template instantiation.
Then you can choose which breakpoints and for which type you want to keep active.

Disassembly

Edit:
You could also add the Function column to the Breakpoints window and see the actual template function.

Sample Image



Related Topics



Leave a reply



Submit