8

I have an arbitrary precision Integer class, which is a lot like Java's BigInteger or OpenSSL's BIGNUM in operation. I'm having trouble understanding how I should express an unbounded limit for numeric_limit<Integer>::max().

Stack Overflow has a couple of question that asks if its OK to do (like Is it ok to specialize std::numeric_limits for user-defined number-like classes?), and some answers with some examples using primitives, but I did not see an example using an arbitrary precision integer class. I also visited std::numeric_limits reference page but its not clear to me what I should do in this situation.

At this point, my takeaway is its OK to specialize numeric_limit for my Integer, and its OK to put it in the standard namespace. I also need to specialize all numeric_limits.

How do I specify an unbounded limit for numeric_limit<T>::max()?


Below is from GCC 4.2.1's <limits> (OS X machine).

/// numeric_limits<int> specialization.
template<>
  struct numeric_limits<int>
  {
    static const bool is_specialized = true;

    static int min() throw()
    { return -__INT_MAX__ - 1; }
    static int max() throw()
    { return __INT_MAX__; }

    static const int digits = __glibcxx_digits (int);
    static const int digits10 = __glibcxx_digits10 (int);
    static const bool is_signed = true;
    static const bool is_integer = true;
    static const bool is_exact = true;
    static const int radix = 2;
    static int epsilon() throw()
    { return 0; }
    static int round_error() throw()
    { return 0; }

    static const int min_exponent = 0;
    static const int min_exponent10 = 0;
    static const int max_exponent = 0;
    static const int max_exponent10 = 0;

    static const bool has_infinity = false;
    static const bool has_quiet_NaN = false;
    static const bool has_signaling_NaN = false;
    static const float_denorm_style has_denorm = denorm_absent;
    static const bool has_denorm_loss = false;

    static int infinity() throw()
    { return static_cast<int>(0); }
    static int quiet_NaN() throw()
    { return static_cast<int>(0); }
    static int signaling_NaN() throw()
    { return static_cast<int>(0); }
    static int denorm_min() throw()
    { return static_cast<int>(0); }

    static const bool is_iec559 = false;
    static const bool is_bounded = true;
    static const bool is_modulo = true;

    static const bool traps = __glibcxx_integral_traps;
    static const bool tinyness_before = false;
    static const float_round_style round_style = round_toward_zero;
};
Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885

2 Answers2

6

The standard says the following about the max member function in §18.3.2.4:

Meaningful for all specializations in which is_bounded != false.

So you should make is_bounded false and specify in the documentation for your class that it does not make sense to call std::numeric_limits<T>::max on it.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • Thanks Christian. Since we have to specialize all of `numeric_limits` what do we return? Does it matter? Or can I just side step it by not providing `numeric_limits::max()` (and risk the wrath of undefined behavior gods)? – jww Dec 23 '16 at 15:18
  • 1
    @jww A [`std::optional`](http://en.cppreference.com/w/cpp/utility/optional) (C++17, in `` before C++17) is one option here. – vsoftco Dec 23 '16 at 15:19
  • 2
    @jww: Perhaps you could do it like some fundemental types do for functions that don't make sense for them, for example `max_exponent` for non-floating-point types. In such cases, a zero value is returned. http://en.cppreference.com/w/cpp/types/numeric_limits/max_exponent – Christian Hackl Dec 23 '16 at 15:22
  • Thanks again Christian. That's what I was thinking too. Give me some time to test things and I'll loop back with an accept. – jww Dec 23 '16 at 15:23
  • @jww: You are welcome. Your question has reminded me that I should check more conditions before using certain `std::numeric_limits` functions. – Christian Hackl Dec 23 '16 at 15:25
  • @vsoftco: Not sure I understand the proposed solution. After all, `max` still needs to return a non-optional `T`. – Christian Hackl Dec 23 '16 at 15:32
  • @ChristianHackl What I meant is that you return an optional which will be `None` (or `false`, I forgot exactly how it's implemented) if `is_bounded` is `false`. So you make `max()` return `optional` instead of `T`. I see this as a decent use case for `optional`. – vsoftco Dec 23 '16 at 15:33
  • @vsoftco: Would that not cause undefined behaviour on every attempt to call `max()`? – Christian Hackl Dec 23 '16 at 15:35
  • @ChristianHackl Why would it cause UB? – vsoftco Dec 23 '16 at 15:37
  • @vsoftco: Because in order to return a `T`, one would have to call `operator*`, and *"The behavior is undefined if `*this` does not contain a value."* http://en.cppreference.com/w/cpp/utility/optional/operator* – Christian Hackl Dec 23 '16 at 15:42
  • @ChristianHackl I was thinking of testing first the `optional` for a value via [std::optional::value_or](http://en.cppreference.com/w/cpp/utility/optional/value_or) or [std::optional::value](http://en.cppreference.com/w/cpp/utility/optional/value). – vsoftco Dec 23 '16 at 15:46
  • @vsoftco: Sorry to be so inquisitive! :) But I still don't get it: For an empty optional, `value_or` will always return its argument, which brings us back to the original question. – Christian Hackl Dec 23 '16 at 15:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/131363/discussion-between-vsoftco-and-christian-hackl). – vsoftco Dec 23 '16 at 15:48
1

concerning this question:

At this point, my takeaway is its OK to specialize numeric_limit for my Integer

The answer is Yes because:

  1. it's a specialisation of a standard template, and

  2. it's specialising for a user-defined type.

From cppreference:

It is allowed to add template specializations for any standard library template to the namespace std only if the declaration depends on a user-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142