A More Debuggable Lambda in Visual Studio

Lambdas are a great addition to the language since C++11, although a problem arises despite the convenience: lambdas are anonymous and thus can create confusions in debugging. Particularly, when the lambda is stored into std::function, a type-erased container, Visual Studio loses track of the lambda's symbol and following the function call becomes a pain.

This recent blog
has shown some latest effort from the Visual Studio team to improve the debugging when calling a std::function, however, it does not help when one wants to inspect a function without calling it, for instance, the content of a std::vector<std::function<...>>.

Actually, it is still possible to indicate the lambda even when it has no name: wrap the lambda along with its file and line information. The wrapper can be further compiled out in the final build so it does not impact the performance.

Considering a lambda is an instance of an anonymous struct, we can benefit from operator inheritance without having to use C++17's invoke or result_of.


template<class F>
struct DebuggableLambda : F
{
	template<class F2>
	DebuggableLambda(F2&& func, const char* file, int line)
		: F(std::forward<F2>(func))
		, file(file)
		, line(line)
	{
	}

	using F::operator();

	const char* file;
	int line;
};

A debuggable lambda wrapper is an object of the lambda's type with extra information, this way it can inherit the callable operator() rather than defining on its own. In order to auto deduce the type from the function parameter, we put it into a free function as the usual way pre-C++17:

template<class F>
auto MakeDebuggableLambda(F&& func, const char* file, int line)
-> DebuggableLambda<typename std::remove_reference<F>::type>
{
	return { std::forward<F>(func), file, line };
}

Note that the lambda can be either lvalue or rvalue and is forwarded to the base class constructor. Finally, we need the macro to acquire file and line information.

	#define DEBUGGABLE_LAMBDA(F)\
	MakeDebuggableLambda(F, __FILE__, __LINE__)

Let's try it with experimental code in Visual Studio 2017 that pushes lambdas both with and without the wrapper into a std::vector, and watch the vector's content:
Imgur
Yay! now it displays the location of that lambda without having to follow the call stack.

The complete code can be found at
https://gist.github.com/TheWisp/26097ee941ce099be33cfe3095df74a6

P.S.

Thanks to the reddit thread, while looking for an improvement I realized it's already possible to jump to the lambda definition from std::function, it's only quite hidden so I believe with some usability improvements it would become much easier to use :)

A More Debuggable Lambda in Visual Studio
Share this