C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Making the converting constructor of std::optional less greedy

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Mon, 18 Dec 2023 19:07:40 -0600
On Sat, 9 Dec 2023 at 01:13, Egor via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
> 07.12.2023 11:15, Egor пишет:
> > Hello!
> >
> > std::optional<T> has a really greedy converting constructor. It
> > accepts almost any type that T is constructible from, and constructs a
> > T from it, even if that type is also convertible to optional<T>.
> > Example: https://gcc.godbolt.org/z/ncsYehW19
> >
> > #include <iostream>
> > #include <optional>
> > #include <source_location>
> >
> > struct A
> > {
> > template <typename T>
> > operator T()
> > {
> > std::cout <<
> > std::source_location::current().function_name() << '\n';
> > return {};
> > }
> > };
> >
> > int main()
> > {
> > std::optional<int> x(A{}); // (1) Calls `operator int`, not
> > `operator optional<int>`.
> > // std::optional<int> y = A{}; // (2) Ambiguous.
> > x = A{}; // (3) Calls `operator int`, not `operator
> > optional<int>`.
> > }
> >
> > This is very confusing in my eyes. std::optional is first type I see
> > in the wild that doesn't play nice with templated conversion operators.
> >
> > I suggest we make this constructor of optional not participate in
> > overload resolution if the argument is convertible to optional<T>.
> >
> > This would make (2) valid, and make all three lines call A::operator
> > optional<T>.
> >
>
> After thinking about it, I'm not sure this is even implementable in the
> first place. This constraint would have to be self-referential, and I
> think those are illegal.
>

It's quite easy, actually; all you have to do is test for convertibility to
an arbitrary hypothetical unambiguous public base class of the class being
constructed. This should be implementable without affecting ABI, I think.

Here's (yet) another example:

struct quack : std::optional<std::string> {
    operator char const*() { return has_value() ? (*this)->c_str() : nullptr; }
};
quack q; // is disengaged
std::optional<std::string> p(q); // throws std::logic_error



> While it might be possible to hack together something that will work in
> practice (I'm thinking stateful metaprogramming), I think it has no
> place in the standard library.
>
> I now think that the correct solution is to add opt-in template argument
> deduction for function templates based on how the return value is used
> (since people are doing this anyway with templated conversion operators,
> it would be nice to give them a safer and more terse way of doing so).
>
> But I expect this to be much more contentious, and since this is the
> first time I'm trying to propose something for standardization, I'm not
> sure I'll be able to push it through.
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2023-12-19 01:07:53