Date: Sat, 9 Dec 2023 13:13:00 +0600
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.
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.
> 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.
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.
Received on 2023-12-09 07:13:06