Document number: N2779=08-0289

Alisdair Meredith
2008-09-17

Concepts for Clause 18: Part 2

The original paper reviewing the language support library for application of concepts was N2619. At the time the feature was not understood well enough (by the author) to support the numeric_limits class template. In addition, the class template initializer_list has been added. This paper suggests constraints for both templates.

Basic Analysis

Numeric limits

There is a clear desire to use numeric_limits from generic code, as its key reason to exist is for code dealing with an arbitrary type to probe for information.

An early mis-understanding in trying to understand this template is that there are really no constaints on the member functions themselves. While it is difficult to work out the necessary operations to compute the limitting values for arbitrary types, that is not how this template works. Instead, the basic implementation returns default values regardless of type, and an explicit specialization is expected for any type that is to be fully supported. Said specializations are not constrained to list the operations used in their implementations, as the specialization is effectively a regular class - there are no dependant names to look up.

There was some thought about defining a NumericLimitType concept so that default implementation could be supplied for the new members added to the numeric_limits template that could be found for valid specializations according to the 03 specification. However, this seems a lot of work for a look-up that will only occur in constrained contexts, for the benefit of a couple of functions. A better approach would be to properly decompose the numeric limits notion into a family of concepts that would solve a more complete set of problems. That analysis is beyond this paper.

Finally, in order to constrain the numeric_limits template a reasonable requirement has to be chosen. The author has selected RegularType as possessing the right set of value-like properties to represent an object that might be useful in a context that we would want to query its numerical properties. This is also a minimal set, to make implementation of the base template reasonable without further constraints.

Initializer lists

Initializer lists were added to support a unified syntax for initialization at the Sophia-Antipolis meeting, 2008. In order to support this syntax in constrained contexts, a minimal useful requirement is placed upon the template.

A further language feature targetting adoption in the CD to be issued from the San Francisco meeting, 2008 is an enhanced for-loop syntax. This syntax will be supported for initializer_lists by providing a concept_map for the Range concept.

Finally, the Container concept can also be supported by initializer_list with the addition of a few simple typedefs, at least one of which is also needed to support the Range concept.

Proposed Wording

Update 18.2.1.1 Class template numeric_limits [numeric.limits]

namespace std {
  template<classRegular T> class numeric_limits {
  public:
    static constexpr bool is_specialized = false;
    static constexpr T min() throw(); { return T(); }
    static constexpr T max() throw(); { return T(); }
    static constexpr T lowest() throw(); { return T(); }
    static constexpr int digits = 0;
    static constexpr int digits10 = 0;
    static constexpr int max_digits10 = 0;
    static constexpr bool is_signed = false;
    static constexpr bool is_integer = false;
    static constexpr bool is_exact = false;
    static constexpr int radix = 0;
    static constexpr T epsilon() throw(); { return T(); }
    static constexpr T round_error() throw(); { return T(); }
    static constexpr int min_exponent = 0;
    static constexpr int min_exponent10 = 0;
    static constexpr int max_exponent = 0;
    static constexpr int max_exponent10 = 0;
    static constexpr bool has_infinity = false;
    static constexpr bool has_quiet_NaN = false;
    static constexpr bool has_signaling_NaN = false;
    static constexpr float_denorm_style has_denorm = denorm_absent;
    static constexpr bool has_denorm_loss = false;
    static constexpr T infinity() throw(); { return T(); }
    static constexpr T quiet_NaN() throw(); { return T(); }
    static constexpr T signaling_NaN() throw(); { return T(); }
    static constexpr T denorm_min() throw(); { return T(); }
    static constexpr bool is_iec559 = false;
    static constexpr bool is_bounded = false;
    static constexpr bool is_modulo = false;
    static constexpr bool traps = false;
    static constexpr bool tinyness_before = false;
    static constexpr float_round_style round_style = round_toward_zero;
  };
...
}

Update 18.8 Initializer lists [support.initlist]p1

Header <initializer_list> synopsis

namespace std {
  template<classObjectType E> class initializer_list {
  public:
    typedef E value_type;
    typedef const E& reference;
    typedef const E& const_reference;
    typedef size_t size_type;

    typedef const E * iterator;
    typedef const E * const_iterator;

    initializer_list();
    size_t size() const; // number of elements
    const E* begin() const; // first element
    const E* end() const; // one past the last element
  };

  template<ObjectType T> concept_map Range<initializer_list<T>> {
    const T * begin( initializer_list<T> c ) { return c.begin(); }
    const T * end( initializer_list<T> c ) { return c.end(); }
  };
}