17

Is there any argument for using the numeric limits macros (e.g. INT64_MAX) over std::numeric_limits<T>? From what I understand numeric_limits is in the standard but the macros are only in C99 so therefore non-standard.

Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
Graeme
  • 4,514
  • 5
  • 43
  • 71

5 Answers5

18

The other answers mostly have correct information, but it seems that this needs updating for C++11.

In C++11, std::numeric_limits<T>::min(), std::numeric_limits<T>::max(), and std::numeric_limits<T>::lowest() are all declared constexpr, so they can be usable in most of the same contexts as INT_MIN and company. The only exception I can think of is compile-time string processing using the # stringification token.

This means that numeric_limits can be used for case labels, template parameters, etc., and you get the benefit of using it in generic code (try using INT_MIN vs. LONG_MIN in template<typename T> get_min(T t);).

C++11 also brings a solution to the issue James Kanze talks about, by adding std::numeric_limits<T>::lowest(), which gives the lowest finite value for all types, rather than the lowest value for integer types and the lowest positive value for floating-point types.

David Stone
  • 26,872
  • 14
  • 68
  • 84
10

Pre C++0x, definitely. INT_MIN and INT_MAX are integral constant expressions; numeric_limits<int>::min() and numeric_limits<int>::max() aren't. <climits> is standard C++, and unless you're dealing with templates (where you don't know whether it's int or long), there's really no reason to bother with the overly complicated solution. (Also: if you're writing templates, don't forget that numeric_limits<int>::min() and numeric_limits<double>::min() represent completely different attributes; if you want the minimum possible value, you'll need numeric_limits<T>::is_integer ? numeric_limits<T>::min() : -numeric_limits<T>::max().)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • I'd add that the integral constant expression argument only counts, if you want to use the values in templates. – Xeo Apr 07 '11 at 11:20
  • @Xeo: That's not true. It also matters when you're initializing a class static. – MSalters Apr 07 '11 at 11:38
  • @MSalters, ? you cannot initialize an integral class static without an integral constant? – Nim Apr 07 '11 at 12:02
  • You can, but then you'll need to define it outside your class. – MSalters Apr 07 '11 at 12:05
  • 1
    @Xeo As a template argument, as the dimension of an array, as a case label, and possibly some other cases I've forgotten. In general, the simple rule is to use the simple solution (`INT_MAX`, etc.) when you know the type, and the complex one (`numeric_limits`) when you don't. – James Kanze Apr 07 '11 at 13:45
  • Note that in some versions of GCC (at least 4.6 and 4.7), you may not get limit macros in C++ due to this bug (fixed for 4.8): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52764 – Trevor Robinson Nov 22 '13 at 21:54
  • @TrevorRobinson This doesn't seem to affect `INT_MAX` or `INT_MIN` (which are so widely used that any compiler where they were missing wouldn't stand a chance of being used). – James Kanze Nov 25 '13 at 10:18
8

If C++, use numeric_limits, end of.

EDIT: Okay, per the comment by James, not "end of." - exceptions are templates and case labels. But, I cannot see a use for having a case label for either min or max, or a template for them, but I guess I've not seen all possibilities...

I guess my point is that the numeric_limits template is more useful beyond max() and min()...

Nim
  • 33,299
  • 2
  • 62
  • 101
  • 1
    Try it in a context where an integral constant expression is required. Say instantiating a template, or in a case lable. Or for smaller types , as an array dimension (`UCHAR_MAX + 1` is frequent). – James Kanze Apr 07 '11 at 10:59
  • @James, hmm.. okay, I'll edit for templates and case labels, not sure about array dimensions though... – Nim Apr 07 '11 at 12:08
  • 5
    Important note: since C++11 `std::numeric_limits::max()` is `constexpr`, so, the exception no longer hold. – juanchopanza May 20 '17 at 06:40
5

Although in C++11 the constants in std::numeric_limits are constexpr so that you can use them in templates etc., there's still at least one scenario when you must use macros from <climits>/<cstdint> instead. It's preprocessor. In C++, preprocessor is as limited as it is in C, so it can't use normal variables, be it a const or constexpr one. Much less so members of structures, and even less so templated structures. Thus you can't do the following:

#include <cstddef>
#include <limits>

// Won't work!
#if std::numeric_limits<std::size_t>::max() > std::numeric_limits<unsigned>::max()
// ...
#endif

Instead, you should resort to the following working (and more readable!) variant:

#include <cstdint>
#include <climits>

// Works fine
#if SIZE_MAX > UINT_MAX
// ...
#endif
Ruslan
  • 18,162
  • 8
  • 67
  • 136
1

In certain contexts (e.g. case labels, non-type template parameters) a numeric constant is expected, and numeric_limits doesn't support this: numeric_limits<int>::max() is not a constant. In case labels, you have to use INT_MAX instead.

This is very annoying but i hear C++11 will fix this.

anatolyg
  • 26,506
  • 9
  • 60
  • 134