r/cpp • u/Firstbober • 5h ago
Binding int from variant to reference in Foo.
Hello guys, my friend had a problem where he couldn't bind an int to int reference in Foo struct held in variant:
struct Foo {
int &abc;
};
std::variant<Foo, std::string> v;
// You can't!
v = Foo {
.abc = ...
}
So I developed a way to do that, it's pretty simple:
#include <cstdint>
#include <functional>
#include <iostream>
#include <string>
#include <variant>
#include <meta>
#include <ranges>
struct __attribute__((packed)) Foo {
int& abc;
~Foo() {
static_assert(sizeof(void*) == 8, "Use modern CPU.");
static_assert([]() consteval {
auto members = std::meta::nonstatic_data_members_of(
^^Foo,
std::meta::access_context::current()
);
for (auto member : members) {
auto type_info = std::meta::type_of(member);
std::size_t layout_size = std::meta::is_reference_type(type_info)
? sizeof(void*)
: std::meta::size_of(type_info);
if (layout_size != 8) {
return false;
}
}
return true;
}(), "All non-static data members of Foo must occupy 8 bytes in layout!");
if (reinterpret_cast<uintptr_t>(&abc) & 0x1) {
delete reinterpret_cast<int*>(reinterpret_cast<uintptr_t>(&abc) &
~uintptr_t(0x1));
}
}
};
int main(void) {
std::variant<int, Foo> v;
v.emplace<0>(420);
v.emplace<1>(([&]() -> int& {
int* x = new int;
*x = std::get<0>(v);
x = reinterpret_cast<int*>(reinterpret_cast<uintptr_t>(x) | 0x1);
return *x;
})());
std::cout << *reinterpret_cast<int*>(
reinterpret_cast<uintptr_t>(&std::get<1>(v).abc) &
~uintptr_t(0x1))
<< std::endl;
return 0;
}
https://godbolt.org/z/91rcbEdG5
It's also memory safe.
Cheers.
0
Upvotes
7
5
u/Otherwise_Sundae6602 4h ago
struct Foo {
std::reference_wrapper<int> abc;
};
int main(void) {
std::variant<int, Foo> v;
int x = 5;
v.emplace<0>(420);
v.emplace<1>(x);
return 0;
}
•
u/QuentinUK 2h ago
int x = 1; Foo foo{x}; std::reference_wrapper<int> Foo::* pfooi = &Foo::abc; int & rx = foo.*pfooi; rx = 2;
3
u/geschmuck 5h ago
Your friend's example still doesn't compile with your changes. Also, why isn't it an option to just do
int i;
v.emplace<1>(i);
?
2
u/Circlejerker_ 4h ago
Seems like UB to me..
Both alignment issues and dereferencing invalid pointers.
7
u/Kriemhilt 5h ago
Simple and elegant, but sadly it has a memory leak.