boostorg / pfr

std::tuple like methods for user defined types without any macro or boilerplate code
https://boost.org/libs/pfr
Boost Software License 1.0
1.32k stars 157 forks source link

Expected to work with Lambdas? #137

Open jonesmz opened 1 year ago

jonesmz commented 1 year ago

Hi, I see in the Limitations section

Boost.PFR library works with types that satisfy the requirements of SimpleAggregate: aggregate types without base classes, const fields, references, or C arrays:

A casual reader may have seen on the internet "Lambdas are just syntax sugar around a struct with operator()", and expect that Boost.PFR would be able to introspect the types of the capture list of a lambda, since they are "just structs".

Sadly, this does not appear to work in Boost.PFR.

#include <boost/pfr/tuple_size.hpp>

void function()
{
    auto lambda = [](void)mutable{};
    using lambda_t = decltype(lambda);
    static_assert(0 == boost::pfr::tuple_size_v<lambda_t>);
}

This gives the error:

D:\builds\cm-systest\system\pub\dists\boost\boost/pfr/detail/fields_count.hpp(285): error C2338: static_assert failed: '====================> Boost.PFR: Type must be aggregate initializable.'
D:\builds\cm-systest\system\pub\dists\boost\boost/pfr/tuple_size.hpp(33): note: see reference to function template instantiation 'size_t boost::pfr::detail::fields_count<T>(void) noexcept' being compiled
        with
        [
            T=lambda_t
        ]

on the visual studio 2022 compiler, with similar errors on clang 16. (Both in C++17 mode, if that makes a difference).

I think it might be helpful for people searching for libraries to do introspection if you clearly document that lambdas are or are not supported in the Limitations section, with a brief explanation of why not (e.g. not aggregate types, because compiler-magic).

schaumb commented 10 months ago

Lambdas are not aggregate types. See: https://eel.is/c++draft/expr.prim.lambda.closure#3

denzor200 commented 10 months ago

Definitely it will not work with lambdas :) Nobody discovered such technique

schaumb commented 10 months ago

(These hacks are listed because if someone wants to experiment with lambdas):


It can check that it is layout compatible with a type list:

    int a;
    bool c;
    auto xx = [a, c] {};
    using type = decltype(xx);

    struct CC {
        int x;
        bool y;
    };

    static_assert(std::is_layout_compatible_v<type, CC>);

Compiler and lambda-specific member getters: GCC uses public variables with double underscore.

int a;
auto l = [a] {};
int& lambda_a = l.__a;

MSVC uses the same named private variables :

int a;
auto l = [a] {};
// somehow get the &decltype(l)::a , ex: https://github.com/martong/access_private