Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

optional<reference_wrapper<T>> vs. optional<T>& - practical examples?

I have read about std::optional<std::reference_wrapper<T>> as a way to pass around optional references.

However, I'm unable to think of a practical example where I'd do that, instead of just using an optional<T>&.

For example, suppose I'm writing a function which needs to take an optional vector<int> by reference.

I could do this:

void f(optional<reference_wrapper<vector<int>>> v) {
    // ...
}

int main() {
    vector<int> v = {1, 2, 3, 4};
    f(make_optional<reference_wrapper<vector<int>>>(std::ref(v));
    return 0;
}

But why not just do this?

void f(optional<vector<int>>& v) {
    // ...
}

int main() {
    f(make_optional<vector<int>>>(std::initializer_list{1, 2, 3, 4}));
    return 0;
}

Please give an example where optional<reference_wrapper<T>> is preferable to optional<T>&. The semantic differences, and especially the ways they can be leveraged in practice aren't clear to me.

like image 309
Aviv Cohn Avatar asked Nov 16 '25 02:11

Aviv Cohn


1 Answers

std::optional<T> & is a reference to an optional object that can own a T object. You can mutate a T (if one is contained) or you can clear the optional object that was passed in by reference, destroying the contained T.


std::optional<std::reference_wrapper<T>> is an optional object that can own a reference to a T, but it doesn't actually own the T itself. The T lives outside of the std::optional object. You can mutate the T (if a reference is contained) or you can clear the optional object, which does not destroy the T. You can also make the optional object point at a different T, but this would be kind of pointless since the caller is passing you an optional by value.

Note that we already have a type built-in to the language that means "optional reference to a T": T*. Both a raw pointer and an optional reference have basically the same semantics: you either get nothing or you get a handle to an object you don't own. In modern C++, a raw pointer is the way to express an optional value not owned by the receiver.

I can't think of a single reason I'd ever explicitly use std::optional<std::reference_wrapper<T>> instead of T*.

like image 182
cdhowie Avatar answered Nov 18 '25 17:11

cdhowie



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!