1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# `rfl::replace`
`rfl::replace` creates a deep copy of the original struct or moves the original struct, replacing one or several fields in the process.
This only works for the `rfl::Field`-syntax.
In some cases, we really only want to change one or a few fields, to get from one struct to another:
```cpp
const auto lisa = Person{
.first_name = "Lisa",
.last_name = "Simpson",
.children = std::vector<Person>()
};
// Returns a deep copy of the original object,
// replacing first_name.
const auto maggie =
rfl::replace(lisa, rfl::make_field<"first_name">(std::string("Maggie")));
```
`maggie` is now a deep copy of `lisa`, but with a new `first_name`.
However, in some cases, we do not want or are unable to create a deep copy of a struct.
For instance, suppose we had put the field `children` into a `rfl::Box`:
```cpp
struct Person {
std::string first_name;
std::string last_name;
rfl::Box<std::vector<Person>> children;
};
```
`rfl::Box` cannot be copied, and if we naively try to apply `rfl::replace` to this,
this will not compile (disabling copies is very much the point of `rfl::Box`).
However, we can use `std::move`:
```cpp
auto lisa = Person{.first_name = "Lisa",
.last_name = "Simpson",
.children = rfl::make_box<std::vector<Person>>()};
const auto maggie = rfl::replace(
std::move(lisa), rfl::make_field<"firstName">(std::string("Maggie")));
```
The fields from `lisa` have now been moved into `maggie`.
We can also remove several fields using `replace`:
```cpp
auto lisa = Person{.first_name = "Lisa",
.last_name = "Simpson",
.children = rfl::make_box<std::vector<Person>>()};
const auto milhouse = rfl::replace(
std::move(lisa),
rfl::make_field<"firstName">(std::string("Maggie")),
rfl::make_field<"lastName">(std::string("Van Houten")));
```
If you have nested structs using `rfl::Flatten`, you can treat the fields inside `rfl::Flatten`
as if they were on the main level:
```cpp
struct Person {
std::string first_name;
rfl::Box<std::string> last_name;
int age;
};
struct Employee {
rfl::Flatten<Person> person;
rfl::Box<std::string> employer;
float salary;
};
auto employee = Employee{
.person = Person{.first_name = "Homer",
.last_name = rfl::make_box<std::string>("Simpson"),
.age = 45},
.employer = rfl::make_box<std::string>("Mr. Burns"),
.salary = 60000.0};
auto employee2 =
rfl::replace(std::move(employee), rfl::make_field<"salary">(70000.0),
rfl::make_field<"age">(46));
```
In this case `age` is part of `Person` and `salary` part ot `Employee`, but
because you have flattened them, you can treat them as if they were on
the same level.
You can also replace structs with other structs. Consider the following example:
```cpp
struct Person {
std::string first_name;
std::string last_name;
int age;
};
struct Employee {
rfl::Flatten<Person> person;
std::string employer;
float salary;
};
const auto employee = Employee{
.person =
Person{.first_name = "Homer", .last_name = "Simpson", .age = 45},
.employer = std::string("Mr. Burns"),
.salary = 60000.0};
const auto carl = Person{.first_name = "Carl", .last_name = "", .age = 45};
const auto employee2 = rfl::replace(employee, carl);
```
This code flattens the employee structs and then replaces all relevant fields with their counterparts contained in `carl`.
Finally, we get this JSON string:
```json
{"first_name":"Carl","last_name":"","age":45,"employer":"Mr. Burns","salary":60000.0}
```
Don't worry, this is fairly optimized and makes heavy use of forwarding. It does not make any copies than it absolutely has to.
|