Date: Wed, 5 Jun 2024 12:16:43 +0100
On 05/06/2024 10:46, Frederick Virchanza Gotham via Std-Proposals wrote:
> On Tue, Jun 4, 2024 at 11:49 PM I wrote:
>>
>> If a programmer doesn't want to use "std::elide" because it fails to
>> be a constructor parameter, then they can use their own elider. Or use
>> "std::elide_nofail".
>
>
> So then the class hierarchy would become:
>
> namespace std {
>
> class elide_base {};
>
> template<typename F, typename... Params>
> class elide : public elide_base { /* implementation */ };
>
> template<typename F, typename... Params>
> class elide_nofail : public elide_base { /* implementation */ };
>
> }
>
> The two classes, "elide" and "elide_nofail" would be identical except
> that the latter doesn't fail to be the sole parameter type of a
> constructor.
>
> If anyone doesn't like the idea of having two separate classes like
> that, then instead the two classes could be one template class
> differentiated by a boolean template parameter, for example:
>
> using elide = elide_base<false>;
> using elide_nofail = elide_base<true>;
>
> Anyone liking the sound of this? Remember, we're not looking for a
> perfect solution, we're looking for the best solution.
No, I very much dislike this.
std::elide has a quirk when facing a single argument constructor. The
standard says that when there are both viable constructors and viable
conversions then the constructor wins, this is an inherent quirk in the
language. Flipping it around doesn't remove the quirk, it's just another
quirk. It's an inherent imbalance of constructors and conversions that
can't be resolved symmetrically.
Adding core language or standard library special treatment to std::elide
might appear to remove this corner case in certain usages, but
ultimately it adds dozens of other corner cases that you might hit more
rarely, but as a result they are more annoying to deal with. It's like
death by a thousand cuts.
In my mental model std::elide is very close to std::reference_wrapper.
std::reference_wrapper is a proxy class for lvalues, while std::elide is
a proxy class for prvalues (and yes, there is a missing proxy class for
xvalues, exercise for the reader). std::reference_wrapper happens to
have a lot of library special treatment that I don't particularly love,
but AFAIK it doesn't have any core language exceptions.
If std::elide invites similar special treatment as
std::reference_wrapper in the library then I would rather not see it in
the standard. It's not a hard class to write, or it could be added to
some 3rd party library, like boost or something else. Maybe it could
follow the distribution model of `overloaded`, which is "copy-paste from
cppreference".
Cheers,
Lénárd
> On Tue, Jun 4, 2024 at 11:49 PM I wrote:
>>
>> If a programmer doesn't want to use "std::elide" because it fails to
>> be a constructor parameter, then they can use their own elider. Or use
>> "std::elide_nofail".
>
>
> So then the class hierarchy would become:
>
> namespace std {
>
> class elide_base {};
>
> template<typename F, typename... Params>
> class elide : public elide_base { /* implementation */ };
>
> template<typename F, typename... Params>
> class elide_nofail : public elide_base { /* implementation */ };
>
> }
>
> The two classes, "elide" and "elide_nofail" would be identical except
> that the latter doesn't fail to be the sole parameter type of a
> constructor.
>
> If anyone doesn't like the idea of having two separate classes like
> that, then instead the two classes could be one template class
> differentiated by a boolean template parameter, for example:
>
> using elide = elide_base<false>;
> using elide_nofail = elide_base<true>;
>
> Anyone liking the sound of this? Remember, we're not looking for a
> perfect solution, we're looking for the best solution.
No, I very much dislike this.
std::elide has a quirk when facing a single argument constructor. The
standard says that when there are both viable constructors and viable
conversions then the constructor wins, this is an inherent quirk in the
language. Flipping it around doesn't remove the quirk, it's just another
quirk. It's an inherent imbalance of constructors and conversions that
can't be resolved symmetrically.
Adding core language or standard library special treatment to std::elide
might appear to remove this corner case in certain usages, but
ultimately it adds dozens of other corner cases that you might hit more
rarely, but as a result they are more annoying to deal with. It's like
death by a thousand cuts.
In my mental model std::elide is very close to std::reference_wrapper.
std::reference_wrapper is a proxy class for lvalues, while std::elide is
a proxy class for prvalues (and yes, there is a missing proxy class for
xvalues, exercise for the reader). std::reference_wrapper happens to
have a lot of library special treatment that I don't particularly love,
but AFAIK it doesn't have any core language exceptions.
If std::elide invites similar special treatment as
std::reference_wrapper in the library then I would rather not see it in
the standard. It's not a hard class to write, or it could be added to
some 3rd party library, like boost or something else. Maybe it could
follow the distribution model of `overloaded`, which is "copy-paste from
cppreference".
Cheers,
Lénárd
Received on 2024-06-05 11:16:45