I am working on using C++26 reflection (P2996) to reflect the capture list of a stateful lambda into a nameable POD struct. My goal is to "abuse" the fact that lambdas are typically implemented as unnamed classes by the compiler. The code has been attached below and is also available on Compiler Explorer here.
I am seeing very different results across the two major reflection implementations:
- Clang (p2996 branch): Correctly mirrors the captures. The output is
Success!It seems Clang treats captures as standard reflectable data members. - GCC (trunk): The output is
Reflection failed: size mismatch (1 vs 16). It appearsnonstatic_data_members_ofreturns an empty range for the closure type, resulting in an empty 1-byte struct.
Does GCC implement lambda captures in a way that fundamentally prevents them from being seen as data members by the reflection engine? Is it the intent of P2996 to eventually support the reflection of lambda capture lists, or is this behavior currently implementation-defined/not accepted? Am I missing something entirely?
#include
#include
#include
#include
template
void try_mirror(Lambda&& l) {
if constexpr (sizeof(M) == sizeof(Lambda)) {
// This is taken in Clang (expected)
auto m = std::bit_cast(l);
std::cout << "Success!\n";
} else {
// This is taken on GCC (why?)
std::cout << "Reflection failed: size mismatch ("
<< sizeof(M) << " vs " << sizeof(Lambda) << ")\n";
}
}
int main() {
int id = 101;
double val = 99.9;
auto lambda = [id, val](int x) { return id + x + (int)val; };
using L = decltype(lambda);
struct Mirror; // Want to send captured members here
consteval {
using namespace std::meta;
constexpr auto ctx = access_context::unchecked();
std::vector specs;
// Was expecting to see all captured members here
template for (constexpr auto c : std::define_static_array(
nonstatic_data_members_of(^^L, ctx)))
{
specs.push_back(data_member_spec(type_of(c), {}));
}
define_aggregate(^^Mirror, specs);
}
try_mirror(lambda);
return 0;
}
Why I am doing this
We are working on automating lambda serialization in HPX. We recently added support for general classes using reflection-based serialization. If a lambda's capture list can be mirrored into a POD struct, our existing serialization infrastructure would be able to handle this.