Search code examples
c++lambdamember-pointers

Create std::function which returns variant with a value of a function member. Segmentation fault


I am writing a wrapper class to wrap custom struct member variables into variants. Given a reference to a struct object, std::function must return a variant, that contains a value of a specific member - with which std::function was initially created. That means, I need to Save a pointer to the specified class member on function creation.

This code compiles, but when I try to invoke the function object, I get segmentation fault. Why does it happen and how to fix it?

#include <functional>
#include <variant>

#include <iostream>

struct Foo
{
    int a,
    b;
    char c;
    double d,
    e;
};

template <typename Struct, typename ... VarTypes>
struct WrapMemberGet
{
    template <typename T>
    static std::function<std::variant<VarTypes...>(const Struct&)>
            WrapGet(T(Struct::*mem_ptr))
    {
                return [&](const Struct& s)
                {
                    return std::variant<VarTypes...>(s.*mem_ptr);
                };
    }
};

int main(int argc, const char **argv)
{
    Foo  f{4, 8, 15, 16, 23};

    auto get_a = WrapMemberGet<Foo, char, int ,double>::WrapGet(&Foo::a);
    std::variant<char, int, double> var = get_a(f); // this must hold int = 4


    return 0;
}

Solution

  • Your WrapGet function takes a pointer to a member function by value, and inside your function that you're capturing that pointer as a reference inside a lambda. That means that after the function ends using the reference inside the lambda is dangling and using it invokes UB.

    To avoid it capture it by value instead to create a local copy inside lambda.

    return [=](const Struct& s)
    {
        return std::variant<VarTypes...>(s.*mem_ptr);
    };