Doc. no.   J16/04-0015=WG21/N1575
Date:        10 February 2004
Project:     Programming Language C++
Reply to:   Beman Dawes <bdawes@acm.org>

Library Technical Report Component Detection (Revision 1)

Motivation
Requirements and Objectives
Design Rationale
Granularity of macros
Transition between the TR and future standards
Names
Proposed additions to the TR
Revision History

Motivation

Because the Library Technical Report (TR) is non-normative, implementers are permitted to ship partial implementations or to not implement the TR at all. At least one vendor has already begun shipping a partial implementation.

Users wishing to write portable programs that use TR components must therefore determine which TR components are actually available.

For example, several Boost libraries already use a component availability macro (BOOST_HAS_HASH) to determine if a non-standard hash map is available. If present, they use hash maps to speed execution, but otherwise rely on std::map.

Similarly, users of the TR may wish to code something like this:

# include <climits>
# ifdef __TR19768_UNORDERED__
#   include <unordered_map>
# else
#   include <map>
# endif

(For brevity, the example above ignores namespace and other naming issues.)

Such usage is portable if the header and component macro are specified as part of the Library TR. If not specified by the TR, then users are forced to develop their own configuration mechanisms to determine TR component availability. This would be a burden for users wishing to write portable code.

A second use case might occur when user code requires TR components, and wishes to issue an explicit error message when they are not present:

# include <climits>
# ifndef __TR19768_UNORDERED__
#   error Standard Library Technical Report 19768 <unordered_map> header required
# endif

Note: This proposal does not deal with the question of how users request that std::tr1 components be made available by an implementation. That is an orthogonal issue, and is already dealt with in the TR working paper.

Requirements and Objectives

To provide a useful level of functionality to users without unduly burdening implementers, a design needs to consider the following as at least objectives if not downright requirements:

  1. Portable and consistent across implementations.

    Rationale: The whole point of specifying component availability reporting in the TR is to ensure it is portable. If component availability reporting is not consistent across implementations, users cannot easily write portable code.
     
  2. Existing standard library implementations already report std::tr1 component availability correctly.

    Rationale: Ensures a smooth transition for users and implementers.

    Implications: Component availability must be reported by presence rather than absence macros (assuming macros are the mechanism). The macros must reside in a current standard library header to ensure that current implementations are already conforming.
     
  3. Falsely reporting a component as not available is acceptable (although obviously not desirable). Falsely reporting a component as available is not acceptable.

    Rationale: Safety. Reliability.
     
  4. Works well with partial implementations of the TR.

    Rationale: Because the TR is non-normative, implementers are not required to provide all components. For example, an implementation may choose not to provide the special functions. Even if an implementation plans future support for the full TR, such full support may take several releases to become available.

    Implication: There needs to be some granularity in the reporting.
     
  5. Low overhead for users of the availability reporting, and no significant cost to programs not concerned with component availability reporting.

    Implications: Component macros should appear in a nominally low-cost header - not <iostream>, for example.
     
  6. Easy to specify, understand, implement, and use.

    Rationale: Feature detection is the appetizer, not the main meal. KISS.
     
  7. Compatible with C language. This may be a red-herring, but we should at least run this proposal by the C committee to see if they have any concerns or suggestions.

    Rationale: Since the C committee has indicated an intent to make the TR Special Functions available to C programmers, the C++ committee should strive to avoid gratuitous incompatibilities with the C language version.

Design Rationale

Much of the design is driven by the Requirements and Objectives.

The <limits> header is chosen as the location of the macros since it best meets requirements (2), (5). Requirement (5) implies the macros are defined in existing headers, so a new header can't be used.

The proposed granularity is based on intuition rather than any hard-and-fast rule. If the granularity is too fine, implementations will diverge through honest confusion, and the names will be hard to remember. If the granularity is too coarse, there will be a mismatch between what components some implementers will wish to actually deliver and what components the macros identify.

Granularity of macros

Pete Becker expressed concern over the fine granularity of the macros in c++std-lib-12274. Discussion followed.

Given that implementers are already shipping partial implementations of the TR, I continue to propose macros with some granularity. I'm not adverse to reducing the granularity somewhat, but I feel it greatly benefits users to have some granularity. Three options are provided so that LWG members have a choice of granularity.

Transition between the TR and future standards

Several LWG members expressed concern over the transition between the TR and future standards.

Notes have been added to the proposal to make it clear to users that in the transition from the TR to future standards, the TR components will not remain in namespace std::tr1 and the configuration macros will disappear.

Proposed Additions to the Library Technical Report

Choose one of the following options:

Option 1 - Single macro, single definition location

After [tr.intro.namespaces] add:

[Note: Should any components specified by  this technical report become part of a future version of the C++ standard, they will be placed in a namespace other than std::tr1. --end note]

After [tr.intro] add:

If and only if all of the components specified by this technical report are supplied by the implementation, the header <climits> shall define the macro __TR19768__. No other header supplied by the implementation shall cause macro __TR19768__ to be defined.

[Note: The macro __TR19768__ will not be defined by future versions of the C++ Standard Library. Future versions of the C++ Standard can be identified by the value of the predefined macro __cplusplus. --end note]

Option 2 - Single macro, multiple definition locations

After [tr.intro.namespaces] add:

[Note: Should any components specified by this technical report become part of a future version of the C++ standard, they will be placed in a namespace other than std::tr1. --end note]

After [tr.intro] add:

If and only if all of the components specified by this technical report are supplied by the implementation, the header <climits> shall define the macro __TR19768__. If and only if a header supplies all of the components specified in this technical report for that header, it shall define macro __TR19768__. No other header supplied by the implementation shall cause macro __TR19768__ to be defined.

[Note: The macro __TR19768__ will not be defined by future versions of the C++ Standard Library. Future versions of the C++ Standard can be identified by the value of the predefined macro __cplusplus. --end note]

Option 3 - Multiple macros

After [tr.intro.namespaces] add:

[Note: Should any components specified by this technical report become part of a future version of the C++ standard, they will be placed in a namespace other than std::tr1. --end note]

After [tr.intro] add:

The availability of components described in this technical report are reported by the presence of the macros described in the Component Availability Macros Table. Each macro shall be defined if and only if the entire component it identifies is available. Each macro definition shall appear in the <climits> header and in all other headers specified by this technical report as containing any part of the component that it identifies. No other header supplied by the implementation shall cause any of these macros to be defined.

[Note: These macros will not be defined by future versions of the C++ Standard Library. Future versions of the C++ Standard can be identified by the value of the predefined macro __cplusplus. --end note]

Component Availability Macros Table

Macro Component
__TR19768__ All. [note - not defined unless all TR19768 components are available. - end note]
__TR19768_UTILITY__ Reference wrappers ([tr.util.refwrp.synopsis])
__TR19768_MEMORY__ Smart Pointers ([tr.util.smartptr])
__TR19768_FUNCTIONAL__ Function objects and higher-order programming. ([tr.func])
__TR19768_TYPE_TRAITS__ Metaprogramming and type traits ([tr.meta])
__TR19768_RANDOM__ Random number generation ([tr.rand])
__TR19768_MATH__ Mathematical special functions ([tr.num.sf])
__TR19768_TUPLE__ Tuple types ([tr.tuple])
__TR19768_UNORDERED__ Unordered associative containers ([tr.hash]) [note - also defined in <functional>. - end note]
__TR19768_REGEX__ Regular expressions ([tr.re])
__TR19768_ARRAY__ Fixed size array wrapper ([TBD])
__TR19768_ITERATOR__ Iterator concepts, facades, and adaptors ([TBD])
__TR19768_C99__ C99 library ([TBD])

Revision History

N1558 - Initial version

N1575 - Revision 1


Copyright Beman Dawes, 2003.

Revised 11 February, 2004