C++ Logo

std-proposals

Advanced search

Re: Make non-specialized numeric_limits<T> use ill-formed

From: John McFarlane <john_at_[hidden]>
Date: Tue, 14 Apr 2020 19:13:23 +0100
On Tue, 14 Apr 2020 at 17:32, Jody Hagins <coachhagins_at_[hidden]> wrote:

>
> On Apr 14, 2020, at 11:26 AM, John McFarlane <john_at_[hidden]> wrote:
>>
>>
>>> The requirements of the original template apply only to the
>>> implementation's representation of the arithmetic types. Since it is
>>> impossible for any user-defined type to satisfy this constraint, it is
>>> impossible for any user defined type to provide a specialization that meets
>>> the standard library requirements for the original template. Thus,
>>> according to the standard itself, the behavior of a program is undefined if
>>> it adds a template specialization for std::numeric_limits.
>>>
>>
>> I don't think that counts as a requirement, more a statement about what
>> numeric_limits does out of the box.
>>
>>>
>>>
>
> I wish that were true. However, that statement is not in the part that
> describes the specializations, but the class template itself - along with
> all the other requirements of the class template. This is even more clear
> when reading it in context as it is paragraph #1 - right before the
> description the primary template.
>

Those are requirements for providers of standard library implementations,
not for users specializing in their own libraries. Paragraph 1 is saying
that the implementer must specialize for provided arithmetic types. That's
not the same as saying that the user must do so also.

cppreference.com is a user-facing resource which clarifies requirements on
the user:

> Non-standard libraries may add specializations
<https://en.cppreference.com/w/cpp/language/extending_std> for
library-provided types, e.g. OpenEXR <http://openexr.com/> provides std::
numeric_limits<half> for a 16-bit floating-point type.
(from "numeric_limits
<https://en.cppreference.com/w/cpp/types/numeric_limits>")

> Specializations of std::numeric_limits
<https://en.cppreference.com/w/cpp/types/numeric_limits> must define all
members declared static const (until C++11)static constexpr (since C++11)
in the primary template, in such a way that they are usable as integral
constant expressions
<https://en.cppreference.com/w/cpp/language/constant_expression>.
(from "Extending the namespace std
<https://en.cppreference.com/w/cpp/language/extending_std>")

HTH
John

>
>
>
>
>
>
> On Apr 14, 2020, at 11:26 AM, John McFarlane <john_at_[hidden]> wrote:
>
> On Tue, 14 Apr 2020 at 15:03, Jody Hagins via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Sorry - that may come across wrong - I'm not trying to bait anyone. I
>> have seen code that provides specializations of numeric_limits, and you
>> assert quite freely that such action is allowed by the standard. However,
>> I have never seen any formal justification that the standard actually
>> allows it. Thus, I would be very interested to see support for such a
>> stance.
>>
>
>> I will quote, C++17 and C++20, but the language in previous standards is
>> similar - though C++20 has extra language to make attempts to provide more
>> restrictions on touch stuff in std.
>>
>>
>> C++17 - 20.5.4.2.1/1 [namespace.std]
>>
>> The behavior of a C++ program is undefined if it adds declarations or
>> definitions to namespace std or to a namespace within namespace std unless
>> otherwise specified. A program may add a template specialization for any
>> standard library template to namespace std only if the declaration depends
>> on a user-defined type and the specialization meets the standard library
>> requirements for the original template and is not explicitly prohibited.
>>
>>
>> C++20 - 16.5.4.2.1/2 [namespace.std]
>>
>> Unless explicitly prohibited, a program may add a template specialization
>> for any standard library class template to namespace std provided that (a)
>> the added declaration depends on at least one program-defined type and (b)
>> the specialization meets the standard library requirements for the original
>> template.
>>
>>
>> Note, in particular, the second condition in both - that the
>> specialization meets the standard library requirements of the original
>> template.
>>
>> Now, let's look at numeric_limits to determine the requirements of the
>> original template.
>>
>>
>> C++17 - 21.3.4/1 [numeric.limits]
>>
>> The numeric_limits class template provides a C++ program with information
>> about various properties of the implementation’s representation of the
>> arithmetic types.
>>
>>
>> C++20 - 17.3.5/1 [numeric.limits]
>>
>> The numeric_limits class template provides a C++ program with information
>> about various properties of the implementation’s representation of the
>> arithmetic types.
>>
>>
>> The requirements of the original template apply only to the
>> implementation's representation of the arithmetic types. Since it is
>> impossible for any user-defined type to satisfy this constraint, it is
>> impossible for any user defined type to provide a specialization that meets
>> the standard library requirements for the original template. Thus,
>> according to the standard itself, the behavior of a program is undefined if
>> it adds a template specialization for std::numeric_limits.
>>
>
> I don't think that counts as a requirement, more a statement about what
> numeric_limits does out of the box.
>
>>
>> Don't get me wrong - I would love to see where the standard allows such
>> specialization. I'm even somewhat OK with implication, but here there
>> seems to be explicit contradiction to such specializations.
>>
>>
>>
>> On Apr 14, 2020, at 8:15 AM, Jody Hagins <coachhagins_at_[hidden]> wrote:
>>
>> Hi John.
>>
>> Please provide support from the standard for your last sentence: "It
>> should although numeric_limits does allow custom specialization."
>>
>>
>>
>>
>> On Apr 14, 2020, at 5:54 AM, John McFarlane via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> On Mon, 13 Apr 2020 at 15:33, Michael Hava via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> *IMHO:* The definition of numeric_limits is rather unfortunate (
>>> is_specialized, min vs lowest, countless members that have no meaning
>>> for certain types, …), but I seriously doubt that we can/should try to
>>> change it after 20+ years…
>>>
>>>
>>>
>>> If anything can be done in this area, it should most probably be a new
>>> facility for these limits that follows a more modern (read: non-monolithic)
>>> design.
>>>
>>
>> See P0437R1
>> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0437r1.pdf> and
>> P1370R1
>> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1370r1.html> for
>> work in this direction.
>>
>> Note: type_traits already exposes some of the functionality of
>>> numeric_limits (is_signed, is_integral, …).
>>>
>>
>>>
>>> Best regards,
>>>
>>> Michael
>>>
>>>
>>>
>>> Food for thought: maybe a new limits-system should include support for
>>> “custom arithmetic types” (e.g. complex,…)
>>>
>>
>> It should although numeric_limits does allow custom specialization.
>>
>> Cheers,
>> John
>>
>>>
>>>
>>> *From:* Std-Proposals <std-proposals-bounces_at_[hidden]> *On
>>> Behalf Of *Thomas Mercier via Std-Proposals
>>> *Sent:* Friday, April 10, 2020 8:27 PM
>>> *To:* std-proposals_at_[hidden]
>>> *Cc:* Thomas Mercier <thomas.mercier.jr_at_[hidden]>
>>> *Subject:* [std-proposals] Make non-specialized numeric_limits<T> use
>>> ill-formed
>>>
>>>
>>>
>>> Hi,
>>>
>>> I encountered some surprising behavior from the std::numeric_limits<T>
>>> class template when experimenting with std::byte. The integer
>>> representation of the maximum std::byte value is 0 according to
>>> std::numeric_limits<std::byte>::max(). That is because there is no
>>> specialization of std::numeric_limits<T> for std::byte, because std::byte
>>> is not an arithmetic type. Ok, fine. But the fact that the program
>>> compiles, and produces an unexpected value is worrisome!
>>>
>>> The standard specifies that "The default numeric_­limits<T> template
>>> shall have all members, but with 0 or false values." (
>>> https://eel.is/c++draft/numeric.limits#3)
>>>
>>> I would prefer to see this say something like, "a program which uses the
>>> default numeric_limits<T> template is ill-formed", so that an error is
>>> produced at compile time rather than a value initialized result (
>>> https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/limits#L321
>>> and
>>> https://github.com/llvm/llvm-project/blob/master/libcxx/include/limits#L150
>>> ).
>>>
>>> Does anyone know why the current wording specifies "0 or false values",
>>> or what any objections to my suggested change might be?
>>>
>>> https://godbolt.org/z/YVSECn
>>>
>>> Thanks,
>>> T.J.
>>> --
>>> 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 mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
>
>

Received on 2020-04-14 13:16:30