problems with C++ integer types

I'm very confused about a number of things related to C++ standard and boost
libraries
dealing with numeric types. Here are a few things that I'm not getting.
a) The standard says in section 18.3.2.1
"Specializations shall be provided for each arithmetic type, both floating
point and integer, including bool.
The member is_specialized shall be true for all such specializations of
numeric_limits."
...
"Non-arithmetic standard types, such as complex<T> (26.4.2), shall not have
specializations."
and it section 18.3.2.4 numeric_limits members
static constexpr bool is_bounded;
"True if the set of values representable by the type is finite. [ Note: All
built-in types are bounded.
This member would be false for arbitrary precision types.-end note ]"
So the question is: if one makes a "numeric type" like std::complex (or safe
integer
which I'm interested in right now). Should one define a specialization for
this new type?
The working is pretty specific, but then I can't see why "is_bounded" is in
there since
all built-in arithmetic types are bounded. Oh I see this now: Required by
LIA-1.
b) boost/type_traits/is_integral.hpp
This file just specializes each arithmetic type supported by the
implementation.
question:Why isn't it just implemented in terms of numeric limits so that
every
thing is always consistent and never "out of sync" It's implementation
returns
true for only the built in types so it seems to me it should be repeating
what
ever happens to already be in numeric_types.
c) my real interest is to implement a type "safe_integer" which can be
used anywhere an integer is used but will trap errors which occur in
the course of implicit conversions and assignements. If I don't specialize
numeric_limits for my new "safe_integer" certain type_traits like is_signed
won't work for it. If I do - them I"m out of sync with is_integral.hpp and
likely out of conformance with the standard - though I'm not sure what the
implications of that might be.
I'm aware that there is related work going on here - bigint and arbitrary
length integers. How do the authors of these libraries plan to address
this.
There are other cases applications where this would also come up
such as modular integer<modulus> , safe_integer_range

On 1/29/2012 3:01 PM, Robert Ramey wrote:
I'm very confused about a number of things related to C++ standard and boost libraries dealing with numeric types. <snip>
All good questions. You're really asking about any user-defined numeric-like type, not just boost ones. Probably best to ask on comp.lang.c++.moderated. If you get an answer there, please post it here. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler wrote:
On 1/29/2012 3:01 PM, Robert Ramey wrote:
I'm very confused about a number of things related to C++ standard and boost libraries dealing with numeric types. <snip>
All good questions. You're really asking about any user-defined numeric-like type, not just boost ones. Probably best to ask on comp.lang.c++.moderated. If you get an answer there, please post it here.
Hmmm - that was good advice. I found
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a6eed812f6c51f9/8fe717943806e700?lnk=gst&q=numeric_limits+specialization#8fe717943806e700
which - among other things says:
"*YOU* are allowed to provide a specialization for a user defined
type. The implementation is not allowed to provide a specialization
for a non-fundamental standard type."
which is the answer to my question.
it also answers indirectly my other questions. In particular
I realize now that boost/type_traits/is_integral.hpp is should't
be implemented in terms of numeric_limits - it's fine the way
it is. Also boost/type_traits/make_signed can't be implemented
in terms of numeric_limits either so IT'S fine the way
it is. If I want have make_signed

I haven't yet read the Usenet article you mentioned in your reply because I want to get out my initial response without influence. [I read it after writing the following. I think my post here is more useful.] ----------------------------------------
From: Robert Ramey Date: Sun, 29 Jan 2012 15:01:10 -0800
I'm very confused about a number of things related to C++ standard and boost libraries dealing with numeric types. Here are a few things that I'm not getting.
a) The standard says in section 18.3.2.1
"Specializations shall be provided for each arithmetic type, both floating point and integer, including bool. The member is_specialized shall be true for all such specializations of numeric_limits." ... "Non-arithmetic standard types, such as complex<T> (26.4.2), shall not have specializations."
and it section 18.3.2.4 numeric_limits members
static constexpr bool is_bounded;
"True if the set of values representable by the type is finite. [ Note: All built-in types are bounded. This member would be false for arbitrary precision types.-end note ]"
So the question is: if one makes a "numeric type" like std::complex (or safe integer which I'm interested in right now). Should one define a specialization for this new type?
In my opinion, the qualifier is if the numeric concept is a (sub)set of the real numbers. If so, then they should have a std::numeric_limits specialization. Your UDT could even have conversions or other interactions with the built-in numeric types. Built-in floating-point: YES Built-in integers (signed or unsigned): YES Built-in characters or Boolean: Logically, NO. Actuality, YES, due to the C++ language defining them as integer types. (And they're usable as such.) UDT arbitrary integer: YES UDT arbitrary floating/real: YES UDT rational: YES UDT arbitrary continued-fraction rational/real: YES Complex: NO Modulo: NO Polynominals: NO (Math) Vectors: NO Matrices: NO Geometry: NO Real numbers can somehow map to some of my "NO" types, but reverse is sane only in degenerate cases (0 imaginary part; degree of 0, 1-element vector, 1x1 matrix), so they don't get numeric-trait specializations. (Many of these can support a zero vs. non-zero dynamic, but make any operator-bool explicit!)
The working is pretty specific, but then I can't see why "is_bounded" is in there since all built-in arithmetic types are bounded. Oh I see this now: Required by LIA-1.
Is-bounded wouldn't apply to arbitrary length/precision types.
b) boost/type_traits/is_integral.hpp
This file just specializes each arithmetic type supported by the implementation.
question:Why isn't it just implemented in terms of numeric limits so that every thing is always consistent and never "out of sync" It's implementation returns true for only the built in types so it seems to me it should be repeating what ever happens to already be in numeric_types.
numeric_limits is for the type's math properties. is_integral is for the type's properties with respect to the C++ type system. It can be used for template meta-programming.
c) my real interest is to implement a type "safe_integer" which can be used anywhere an integer is used but will trap errors which occur in the course of implicit conversions and assignements. If I don't specialize numeric_limits for my new "safe_integer" certain type_traits like is_signed won't work for it. If I do - them I"m out of sync with is_integral.hpp and likely out of conformance with the standard - though I'm not sure what the implications of that might be.
I'm aware that there is related work going on here - bigint and arbitrary length integers. How do the authors of these libraries plan to address this.
There are other cases applications where this would also come up such as modular integer<modulus> , safe_integer_range
and who know what else. Any useful information/insight would be appreciated.
The "modular integer<modulus>" is the only one of these that should NOT get a specialization for numeric_limits. All of the others conceptually represent real-number values, and therefore should. None of these types are built-ins, and therefore NEVER should get a is_integral specialization. Daryle W.

From: John Date: Tue, 31 Jan 2012 16:28:41 +0000
Modulo: NO
Integer types that are bounded (fixed precision) and implement modular arithmetic (ie built-in integers on most/all platforms) can and should set is_modulo field to true.
Yes, but that's not what I'm talking about. The built-in integers model a subset of real numbers, and the modulo properties (if present on the hardware) are a side-effect of the wrap-around mechanic. This isn't the case with an intentional modulo type (with arbitrary modulus). For instance, if we have a modulo-5 UDT, then the value "1" represents not just 1, but any integer that can be expressed as 5x + 1. Since the state represents a whole class of numbers, it doesn't model to real numbers any more than a polynomial type does. Daryle W.

on Tue Jan 31 2012, Daryle Walker
From: John Date: Tue, 31 Jan 2012 16:28:41 +0000
Modulo: NO
Integer types that are bounded (fixed precision) and implement modular arithmetic (ie built-in integers on most/all platforms) can and should set is_modulo field to true.
Yes, but that's not what I'm talking about. The built-in integers model a subset of real numbers, and the modulo properties (if present on the hardware) are a side-effect of the wrap-around mechanic. This isn't the case with an intentional modulo type (with arbitrary modulus). For instance, if we have a modulo-5 UDT, then the value "1" represents not just 1, but any integer that can be expressed as 5x + 1. Since the state represents a whole class of numbers, it doesn't model to real numbers any more than a polynomial type does.
I think that's a valid, but pretty twisted, way to look at it. An instance of a modulo-5 UDT only represents a whole class of numbers if that's dictated by the way it's being used. It's no more intrinsically a representative of a class than it is an individual. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Daryle Walker wrote:
I haven't yet read the Usenet article you mentioned in your reply because I want to get out my initial response without influence. [I read it after writing the following. I think my post here is more useful.]
----------------------------------------
From: Robert Ramey Date: Sun, 29 Jan 2012 15:01:10 -0800
I'm very confused about a number of things related to C++ standard and boost libraries dealing with numeric types. Here are a few things that I'm not getting.
a) The standard says in section 18.3.2.1
"Specializations shall be provided for each arithmetic type, both floating point and integer, including bool. The member is_specialized shall be true for all such specializations of numeric_limits." ... "Non-arithmetic standard types, such as complex<T> (26.4.2), shall not have specializations."
and it section 18.3.2.4 numeric_limits members
static constexpr bool is_bounded;
"True if the set of values representable by the type is finite. [ Note: All built-in types are bounded. This member would be false for arbitrary precision types.-end note ]"
So the question is: if one makes a "numeric type" like std::complex (or safe integer which I'm interested in right now). Should one define a specialization for this new type?
In my opinion, the qualifier is if the numeric concept is a (sub)set of the real numbers. If so, then they should have a std::numeric_limits specialization.
It seemed to me that any type which "acts like a number" should have such a specialization. I had interpreted the quote from the standard as an admonition that one should not specialize std::numeric_limits for one's own types. I had overlooked the phrase "non-arithimetic standard types". In my case my types IS arithmetic and it's NOT standard so the above wouldn't apply. So I concluded that my concerns were a false alarm. So, I've implemented a specialization of std::numeric_limits for my special kind of integer - which is OK by me. BUT, now I wonder about the idea if placing my own code into the std namespace which I would guess might raise other issues.
Built-in floating-point: YES Built-in integers (signed or unsigned): YES Built-in characters or Boolean: Logically, NO. Actuality, YES, due to the C++ language defining them as integer types. (And they're usable as such.) UDT arbitrary integer: YES UDT arbitrary floating/real: YES UDT rational: YES UDT arbitrary continued-fraction rational/real: YES
Complex: NO Modulo: NO Polynominals: NO (Math) Vectors: NO Matrices: NO Geometry: NO
I would say modular integer or float: definitely yes. decimal floats: definitely yes. polynomials: maybe if the are used to render numbers. Heck any radix based numbers numbers rendered as rational numbers: yes big/unbounded integers: definitely yes arbitray precision numbers: definitely yes. geometry, matrices, vectors, etc.: not likely e.g.rational numbers rendered as a quotient of two integers bounded = true e.g.rational numbers rendered as a quotient of two arbitray length integers bounded = false etc. ...
The working is pretty specific, but then I can't see why "is_bounded" is in there since all built-in arithmetic types are bounded. Oh I see this now: Required by LIA-1.
Is-bounded wouldn't apply to arbitrary length/precision types.
I would say it applies and that it's value should be false.
b) boost/type_traits/is_integral.hpp
numeric_limits is for the type's math properties.
Actually, it's not at all clear to me what the intended purpose is.
is_integral is for the type's properties with respect to the C++ type system. It can be used for template meta-programming.
I was surprised to find that is_integral, is is_signed, etc are not implemented in terms of numeric_limits but rather are implemented for just the built in types. This leads to the current situation: I create a new type of integer:safe_integer, modular_integer or .... which is intended to be used anyware an int or unsigned int can be used. This intention is frustrated when I use is_signed< modular_integer > ... /compile error but is_isigned<int> is OK The current situation is "don't do that" - OK - but it means that I can't implement anything that "works like an int" except for int itself. This seems to be to violate what I would have expected the intention of numeric_limits to be. If it can't do this - what was it intended to be used for? if type_traits for built in types don't use it - then why create it in the first place. I'm not advocating for changing anything. I'm just trying to figure out what this thing is good for.
The "modular integer<modulus>" is the only one of these that should NOT get a specialization for numeric_limits.
100 % disagree with this. It seems to me that this is the ideal use case for numeric_limits. Note that there a number of small but annoying ambiguities here. e.g. unsigned int acts like a modular integer - it rolls over without problem. But compilers may emit warnings when overflow might occur. I haven't looked at the is_modulo value for unsigned int. I'm guessing that numeric_limits isn't used to the extent that it was originally intended.
All of the others conceptually represent real-number values, and therefore should. None of these types are built-ins, and therefore NEVER should get a is_integral specialization.
This distinction between built-ins add-ins is the source of my consternation. In principle, I would like to replace/extend any built-in type with my own special variant. Which I can do. What's not clear is what should be done with regards to numeric_limits for this new type. Ideally, by specializing numeric_limits for my new type I should be able to get "free" benefits from programs which use numeric_limits to affect their behavior. Robert Ramey

AMDG On 01/31/2012 09:45 AM, Robert Ramey wrote:
So, I've implemented a specialization of std::numeric_limits for my special kind of integer - which is OK by me. BUT, now I wonder about the idea if placing my own code into the std namespace which I would guess might raise other issues.
C++ 2003, 17.4.3.1: "A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template." In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
On 01/31/2012 09:45 AM, Robert Ramey wrote:
So, I've implemented a specialization of std::numeric_limits for my special kind of integer - which is OK by me. BUT, now I wonder about the idea if placing my own code into the std namespace which I would guess might raise other issues.
Well this is sort of interesting. So it seems that I'm off the hook as far as specializing numeric_limits if I follow a couple of rules. Now it only remains to decipher the rules.
C++ 2003, 17.4.3.1: "A program may add template specializations for any standard library template to namespace std.
OK - got it.
Such a specialization (complete or partial) of a standard library template results in undefined behavior
Hmmm - not getting this. How does specialization result in undefined behavior. The whole purpose of specialization is to define behavior. Does this mean to say that any declared specialization should be defined or what?
unless the declaration depends on a user-defined name of external linkage
I can't see how this is related to anything. Why should I not be able to define a specialization locally in one file?
and unless the specialization meets the standard library requirements for the original template."
As far as I can tell. numeric_limits<T> specifies no requirements on T other than if numeric_limits is specialized for T should also be specialized for cv variations on T. OK that I get. No one should feel obligated to answer these questions for reasons other than pure enjoyment. I'm not hung up on them.
In Christ, Steven Watanabe

Such a specialization (complete or partial) of a standard library template results in undefined behavior
Hmmm - not getting this. How does specialization result in undefined behavior. The whole purpose of specialization is to define behavior. Does this mean to say that any declared specialization should be defined or what?
unless the declaration depends on a user-defined name of external linkage
[snip]
and unless the specialization meets the standard library requirements for the original template."
[snip]
I think the second part just means that the compiler/library can assume that all specializations of a standard library template meet the requirements for the template (assuming of course that the main definition in the library does), and so if you provide a specialization that does not meet the requirements, the resulting behaviour is undefined. For example, a requirement of std::swap is that it has the effect of exchanging the values stored in two variables passed to it. You can specialize std::swap for some custom type Foo, but if that specialization does not meet the requirement (i.e. it does not exchange the values), then undefined behaviour could result (for example, an algorithm that uses std::swap could get into an infinite loop). I'm not sure what is the purpose of the first part (about linkage). Regards, Nate

On 1/31/12 4:09 PM, Robert Ramey wrote:
Steven Watanabe wrote:
AMDG
On 01/31/2012 09:45 AM, Robert Ramey wrote:
So, I've implemented a specialization of std::numeric_limits for my special kind of integer - which is OK by me. BUT, now I wonder about the idea if placing my own code into the std namespace which I would guess might raise other issues.
Well this is sort of interesting. So it seems that I'm off the hook as far as specializing numeric_limits if I follow a couple of rules. Now it only remains to decipher the rules.
C++ 2003, 17.4.3.1: "A program may add template specializations for any standard library template to namespace std. OK - got it. Such a specialization (complete or partial) of a standard library template results in undefined behavior Hmmm - not getting this. How does specialization result in undefined behavior. The whole purpose of specialization is to define behavior. Does this mean to say that any declared specialization should be defined or what?
unless the declaration depends on a user-defined name of external linkage I can't see how this is related to anything. Why should I not be able to define a specialization locally in one file? This provides the exception to undefined behavior above. Note that this says that the TEMPLATE ARGUMENT must have external linkage, not that the specialization needs to be seen globally. Note though, by the One Definition Rule, if another files defines a specialization for the same template arguments, the definition must be identical.
and unless the specialization meets the standard library requirements for the original template." As far as I can tell. numeric_limits<T> specifies no requirements on T other than if numeric_limits is specialized for T should also be specialized for cv variations on T. OK that I get.
It defines a list of members to be defined, and the type of those members. Your specialization needs to define these same members, and they need to have the specified type. Also, for numeric_limits<T> any specialization needs to have a member "static const bool is_specialize = true;"
No one should feel obligated to answer these questions for reasons other than pure enjoyment. I'm not hung up on them.
In Christ, Steven Watanabe
-- Richard Damon

on Tue Jan 31 2012, "Robert Ramey"
Steven Watanabe wrote:
AMDG
On 01/31/2012 09:45 AM, Robert Ramey wrote:
So, I've implemented a specialization of std::numeric_limits for my special kind of integer - which is OK by me. BUT, now I wonder about the idea if placing my own code into the std namespace which I would guess might raise other issues.
Well this is sort of interesting. So it seems that I'm off the hook as far as specializing numeric_limits if I follow a couple of rules. Now it only remains to decipher the rules.
C++ 2003, 17.4.3.1: "A program may add template specializations for any standard library template to namespace std.
OK - got it.
Such a specialization (complete or partial) of a standard library template results in undefined behavior
Hmmm - not getting this. How does specialization result in undefined behavior. The whole purpose of specialization is to define behavior. Does this mean to say that any declared specialization should be defined or what?
"Undefined behavior" is a technical term, so it has specific meaning having nothing to do with what you mean when you say "the purpose... is to define behavior." To boil it down to basics, the standard is saying that on an arbitrary standard C++ implementation, unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template you've done something illegal and all bets are off. And note, the type_traits, like is_arithmetic, are not open to extension by users. Those traits check fundamental type properties, and the set of arithmetic types (for example) is defined by the standard. Therefore the "meets the standard library requirements" restriction means you your user-defined numeric type is not an arithmetic type in the is_arithmetic sense. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (8)
-
Daryle Walker
-
Dave Abrahams
-
Eric Niebler
-
John Maddock
-
Nathan Ridge
-
Richard Damon
-
Robert Ramey
-
Steven Watanabe