Yes, I used the comparison to vector to show that both approaches are already present in the standard, not as an example of consistency.

In this regards, what I propose is similar to new and and new(std::nothrow). But the semantics in this case is different, as nothrow is not introducing any ub in any case, just requires to check the resulting pointer, so better to use another constant, as std::unchecked.

El dj., 5 de nov. 2020, 20:54, Ryan P. Nicholl <rnicholl@protonmail.com> va escriure:
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@protonmail.com
Work Email: ryan.nicholl@microsoft.com
Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D






-------- Original Message --------
On Nov 5, 2020, 13:27, Jordi Vilar via Std-Proposals < std-proposals@lists.isocpp.org> 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@lists.isocpp.org> 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
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@lists.isocpp.org> 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@protonmail.com
Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D


‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Sunday, October 25, 2020 8:50 PM, Barry Revzin <barry.revzin@gmail.com> wrote:



On Sun, Oct 25, 2020 at 7:41 PM Ryan P. Nicholl via Std-Proposals <std-proposals@lists.isocpp.org> 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@protonmail.com
Tox: 52B3A61CDAF88BCC854F568933F071E3530600CDBA3D5354AADC9AD179575D68021AE959719D

You can achieve this by using std::get_if() and marking the nullptr case as unreachable. For example:

auto f(std::variant<intdouble>& v) -> int* {
    return std::get_if<int>(&v);
}

auto g(std::variant<intdouble>& 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@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals


--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals