Reputation: 3640
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;
}
Upvotes: 2
Views: 159
Reputation: 2850
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);
};
Upvotes: 4
Reputation: 217478
capture by copy to avoid dangling reference:
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);
};
}
Upvotes: 3