C++ Logo

STD-PROPOSALS

Advanced search

Subject: Re: [std-proposals] std::as
From: Ryan P. Nicholl (rnicholl_at_[hidden])
Date: 2020-11-05 13:54:37


std::unchecked would work. But I don't like how you have both under "get" in comparison to e.g. vector where the overloads are separate. Feels inconsistent.

More generally, std::as could be overloaded to work on unions too.

--
Ryan P. Nicholl
Tel: (678)-358-7765
Personal Email: rnicholl_at_[hidden]
Work Email: ryan.nicholl_at_[hidden]
Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D
-------- Original Message --------
On Nov 5, 2020, 13:27, Jordi Vilar via Std-Proposals wrote:
> I understand the problem you are trying to solve, it is a quite common pattern, being in an execution path in which we know the alternative held by the variant. For instance:
>
> if (has_alternative<alternative_type>(variant_object))
> {
> // it is now safe to get the alternative without checking.
> }
>
> but for this escenario, it is possible to do
>
> if (auto *alternative = std::get_if<alternative_type>(&variant_object))
> {
> // it is now safe to dereference the alternative pointer
> }
>
> I know, it is ugly and doesn't communicate properly the intent.
>
> This is the same case as avoiding the range check in std::vector::at() with std::vector::operator[]() subscript operator in:
>
> if (i < vector.size())
> {
> // it is now safe to do vector[i]
> }
>
> In this case, for historical reasons we have both methods. But in case of requiring this optimized path for variants, I would suggest to not adding a new function and pollute even more the std with different names for different patterns/idioms but overloading the current std::get with an overload discriminant object like std::nothrow:
>
> auto& variant = std::get<variant_type>(variant, std::nothrow);
>
> Or we could define a new std::nocheck constant to be reused in any other unchecked overload. In this way, the intent is clear.
>
> Invoking std::get with std::nothrow (or std::nocheck or whatever other symbol we could propose) would be undefined behavior when calling it when the variant holds a different alternative as subscript operator does when performing an out of bounds access to a std::vector. It is elegant, clear, safe and efficient.
>
> I hope this proposal helps,
>
> Jordi Vilar
>
> Missatge de Avi Kivity via Std-Proposals <std-proposals_at_[hidden]> del dia dj., 5 de nov. 2020 a les 18:10:
>
>> How can the reader of *get_if() tell if the author intended this optimization, or was just lazy?
>>
>> Function names should communicate intent. "get_if()" communicates that you don't know if the variant holds the the type you are asking for or not. *get_if() communicates that you forgot to check.
>>
>> My preference would be static_variant_cast<>, following static_cast<> and static_pointer_cast<>. The latter two communicate that the author knows there is a safety violation if some other check is not performed, and confirms they are aware of it, enough to have typed such a long and ugly name.
>>
>> On 26/10/2020 03.25, Tony V E via Std-Proposals wrote:
>>
>>> I don't think you need unreachable.
>>> *get_if should be enough. Unconditionally dereference the result.
>>>
>>> Sent from my BlackBerry portable Babbage Device
>>> From: Justin Bassett via Std-Proposals
>>> Sent: Sunday, October 25, 2020 9:16 PM
>>> To: Std-Proposals
>>> Reply To: std-proposals_at_[hidden]
>>> Cc: Justin Bassett
>>> Subject: Re: [std-proposals] std::as
>>>
>>> I'm glad to see that clang can also optimize this get_if access; it used to be unable to do so. MSVC is also unable to optimize this when using __assume ( https://docs.microsoft.com/en-us/cpp/intrinsics/assume?view=vs-2019 ) (which is the same as Clang's __builtin_assume() https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume ) instead of __builtin_unreachable().
>>>
>>> In theory, a portable __builtin_unreachable() would be:
>>>
>>> [[noreturn]]
>>> inline void unreachable() {} // basically, unconditionally trigger undefined behavior
>>>
>>> In practice, only GCC seems to recognize this.
>>>
>>> --Justin Bassett
>>>
>>> On Sun, Oct 25, 2020 at 5:59 PM Ryan P. Nicholl via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>>
>>>> [build] C:\Users\Ryan\rpnx-core\private\sources\all\test3.cpp(119,5): error C3861: '__builtin_unreachable': identifier not found [C:\Users\Ryan\rpnx-core\build\rpnx-core-test3.vcxproj]
>>>>
>>>> Great idea, except that __builtin_unreachable() is a GCC specific extension, and is not part of standard C++. (It would be nice to be able to do this in a cross platform way though! But that is for another discussion.)
>>>>
>>>> --
>>>> Ryan P. Nicholl
>>>> Tel: (678)-358-7765
>>>> Personal Email: rnicholl_at_[hidden]
>>>> Work Email: ryan.nicholl_at_[hidden]
>>>> Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D
>>>>
>>>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>>>> On Sunday, October 25, 2020 8:50 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:
>>>>
>>>>> On Sun, Oct 25, 2020 at 7:41 PM Ryan P. Nicholl via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>>>>
>>>>>> I decided to implement a new class based on std::variant. I call it "rpnx::derivator", but it's basically "allocating_variant". I tried to make it as similar to std::variant as possible. When looking at this, I noticed something weird about std::variant. There is no "zero overhead" way to get the element contained by the variant, as std::get<I> checks for invalid access and throws an exception if invalid. To solve this issue, I would like to propose std::as, which works the same as std::get, but accessing the wrong type is undefined behavior instead of throwing an exception.
>>>>>>
>>>>>> --
>>>>>> Ryan P. Nicholl
>>>>>> Tel: (678)-358-7765
>>>>>> Personal Email: rnicholl_at_[hidden]
>>>>>> Work Email: ryan.nicholl_at_[hidden]
>>>>>> Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D
>>>>>
>>>>> You can achieve this by using std::get_if() and marking the nullptr case as unreachable. For example:
>>>>>
>>>>> auto f(std::variant<int, double>& v) -> int* {
>>>>> return std::get_if<int>(&v);
>>>>> }
>>>>>
>>>>> auto g(std::variant<int, double>& v) -> int* {
>>>>> auto p = std::get_if<int>(&v);
>>>>> if (not p) __builtin_unreachable();
>>>>> return p;
>>>>> }
>>>>>
>>>>> On -O1, f emits a check but g does not: https://godbolt.org/z/9G9fd5.
>>>>>
>>>>> Barry
>>>>
>>>> --
>>>> Std-Proposals mailing list
>>>> Std-Proposals_at_[hidden]
>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals



STD-PROPOSALS list run by std-proposals-owner@lists.isocpp.org

Standard Proposals Archives on Google Groups