rttr icon indicating copy to clipboard operation
rttr copied to clipboard

Automatic variant conversion to `std::reference_wrapper`

Open jgehring opened this issue 7 years ago • 6 comments

I really like being able to bind fields of a struct as properties using the as_reference_wrapper policy. However, it's pretty cumbersome to set property values as I need an explicit std::reference_wrapper instance. Consider the following example:

struct S {
  int v = 0;
};

RTTR_REGISTRATION {
  rttr::registration::class_<S>("S")
    .constructor()
    .property("v", &S::v)(rttr::policy::prop::as_reference_wrapper);
}

void test() {
  auto type = rttr::type::get<S>();
  auto inst = type.create();
  std::cout << type.get_property("v").get_value(inst).to_int() << std::endl;

  // 1) Set property via value: doesn't work, ok will be false
  auto ok = type.get_property("v").set_value(inst, 2);

  // 2) Try to convert value to desired type: doesn't work, ok will be false
  auto var = rttr::variant(2);
  ok = var.convert(type.get_property("v").get_type());

  // 3) Create explicit value and wrapper: this works
  auto value = 2;
  auto wrapper = std::reference_wrapper<int>(value);
  ok = type.get_property("v").set_value(inst, wrapper);
}

It would be nice if variants would be convertible to values to std::reference_wrapper. Not sure if this is easily possible but it would make registration of structs quite convenient :)

jgehring avatar Sep 21 '17 08:09 jgehring

This will not work. The value is copied inside the variant, when you now make a reference inside the variant, the value will be gone and you will hold a dangle reference. Here is the condition, whether you can convert a value to a wrapper class inside a variant: https://github.com/rttrorg/rttr/blob/master/src/rttr/detail/type/type_data.h#L249 E.g. for std::shared_ptr it will work.

acki-m avatar Sep 22 '17 07:09 acki-m

Yeah, agree re conversion to a reference_wrapper. However, if the type in question is copy-constructible it should still be possible to change a property exposed via prop::as_reference_wrapper via a variant that holds a plain value? Currently, it's difficult to set such a property in a generic way, i.e. if you can't instantiate the actual type that's required manually.

A similar issue arises when working with pointers -- I can't see how I can convert a variant holding an int* to int, for example. What do you think about making it possible to reference and dereference variants, i.e. not via conversion but by creating a new variant? Something like this maybe:

int i = 0;
rttr::variant v = i; // v holding int
auto vref = rttr::variant::ref(v); // vref holding std::reference_wrapper<int>
auto vptr = rttr::variant::addr(v); // vptr holding int*
auto vderef = rttr::variant::deref(vptr) // performs a copy, vderef holding int

jgehring avatar Sep 22 '17 07:09 jgehring

This is an interesting approach, i reopen the issue.

acki-m avatar Sep 25 '17 19:09 acki-m

using prop::as_reference_wrapper doesn't work for me

class MyClass
{
	RTTR_ENABLE()
	RTTR_REGISTRATION_FRIEND

private:
	std::unique_ptr<uint32_t>	mInt32UPtr;
};

RTTR_REGISTRATION
{
	rttr::registration::class_<MyClass>("MyClass")
	.property("mInt32UPtr", &MyClass::mInt32UPtr) // error MSVC VS2017 15.9.15: \rttr\detail\property\property_accessor.h(45): error C2280: attempting to reference a deleted function
	(
		rttr::policy::prop::as_reference_wrapper
	)
;
}

emikita avatar Sep 12 '19 10:09 emikita

int i = 0; rttr::variant v = i; // v holding int auto vref = rttr::variant::ref(v); // vref holding std::reference_wrapper auto vptr = rttr::variant::addr(v); // vptr holding int* auto vderef = rttr::variant::deref(vptr) // performs a copy, vderef holding int

@acki-m are these ref/addr/deref functions implemented already ? or are they planned ?

bruceauyeung avatar Apr 29 '20 08:04 bruceauyeung

These methods would help a lot. I'm trying to run a meta function that takes in a reference, but I have a pointer. I've tried cast but that copies it. I can't think of anything else.

SeanOMik avatar Dec 24 '22 05:12 SeanOMik