Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is the ctor of optional<T&> explicit? #99

Open
ImplOfAnImpl opened this issue Nov 24, 2021 · 6 comments
Open

Why is the ctor of optional<T&> explicit? #99

ImplOfAnImpl opened this issue Nov 24, 2021 · 6 comments

Comments

@ImplOfAnImpl
Copy link

I mean the ctor template <class U> explicit optional(const optional<U&>& rhs). It doesn't seem to have much sense - optional<T&> is logically a reference and it seems reasonable to allow it to be converted implicitly if the underlying pointer types allow this.
With the current implementation the usage of optional references can be cumbersome, because even the non-const-ref to const-ref conversion has to be explicit.

@akrzemi1
Copy link
Member

This is for consistency with the non-reference specialization: optional<U> is not implicitly convertible to optional<T> even if U is convertible to T.

The missing T-to-const T can indeed be disturbing. This is also the case for non-references:

boost::optional<int> oi;
boost::optional<const int> oci = oi;

We could consider special casing the T-to-const T conversion.

@ImplOfAnImpl
Copy link
Author

I see. But does this consistency actually make sense? I mean, for value types the implicit conversion can indeed do nasty stuff like slicing or narrowing, but converting references seems to always be benign.

Btw, both kinds of optional have assignment operators corresponding to explicit ctors, which kind of defeats the purpose, because you can still perform an implicit conversion:

boost::optional<float> of;
boost::optional<int> oi;
oi = of;

So it might make sense to make boost::optional<T> behave like std::optional in this regard, i.e. the converting ctor is implicit if the underlying types are implicitly convertible to each other (and the assignment is present only of the underlying types are assignable). In this case making ctors of boost::optional<T&> implicit will actually make it consistent with boost::optional<T>.

@akrzemi1
Copy link
Member

akrzemi1 commented Nov 24, 2021

Unless the binding of temporaries to lvalue references to const is explicitly disabled., even the reference casts have the same problems:

  int i = -1;
  unsigned const& ui = i;

Consistency with std::optional is not necessarily a good thing, as std::optional has design flaws that cause ambiguities:

template <typename T, typename U>
void test_optional()
{
  std::optional<U> ou = std::nullopt;
  std::optional<T> ot = ou;
  assert (ot == std::nullopt); // true for some Ts and Us, false for other Ts and Us.
}

The above looks like an obvious thing to expect, but fails for

test_optional<std::optional<int>, int>();

boost::optional has fewer gotchas like the one above, because it does not try to be 100% consistent with std::optional.

@ImplOfAnImpl
Copy link
Author

Unless the binding of temporaries to lvalue references to const is explicitly disabled. Even the reference casts have the same problems

Yes, I meant converting lvalue references of course (there is no boost::optional<T&&> anyway).

Consistency with std::optional is not necessarily a good thing

I see.

@akrzemi1
Copy link
Member

Would allowing a conversion from T to const T address your issue?
Or conversion from Derived& to Base&?

@ImplOfAnImpl
Copy link
Author

Well, the absence of the T& to const T& conversion is what caused me to report the issue.
But IMO the conversion from Derived& to Base& would also be nice to have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants