ISO/IEC JTC1 SC22 WG21 N3256 = 11-0026 - 2011-02-27
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
Alberto Ganesh Barbati, ganesh@barbati.net
Introduction
Freestanding Implementations
GB 55 Freestanding <ratio> and <chrono>
GB 56 Freestanding <utility> and <tuple>
GB 57 Freestanding <atomic>
C1X Freestanding Compatibility
GB 90 Freestanding <type_traits>
At Least as Much as C
17.6.1.3 Freestanding implementations [compliance]
Avoid Large Implementations
17.6.1.3 Freestanding implementations [compliance]
Avoid Threading
17.6.1.3 Freestanding implementations [compliance]
Allow Small Helpers
17.6.1.2 Headers [headers]
17.6.1.3 Freestanding implementations [compliance]
20.? Helper components [helpers]
20.3.2 20.?.1 swap [utility.swap]
20.3.3 20.?.2 forward/move helpers [forward]
20.3.4 20.?.3 Function template declval
[declval]
20.3 Utility components [utility]
Allow <utility> and <tuple>
17.6.1.3 Freestanding implementations [compliance]
Conditional Features
DE 13 Strict Pointer Macro
GB 107 Monotonic Clock Macro
DE 23 Threads Macro
C1X Conditional Feature Compatibility
Remove Conditional Contents
17.6.1.3 Freestanding implementations [compliance]
30.3 Threads [thread.threads]
Add Predefined Macros
16.8 Predefined macro names [cpp.predefined]
Add Library-Defined Macros
17.6.1.2 Headers [headers]
17.6.1.3 Freestanding implementations [compliance]
18.? Library header support [header.support]
Several issues have centered on the requirements on freestanding implementations and the indication of conditionally supported behavior. We list those issues, discuss the general problems, propose solutions, and provide wording.
C++ has no defined policy for choosing what belongs in freestanding headers and what does not. As a consequence, this aspects of the standard is incomplete and inconsistent.
The C++ working draft N3225 requires freestanding implementations to provide: <atomic> <exception> <initializer_list> <limits> <new> <cstdarg> <cstddef> <cstdlib> <thread> <type_traits> <typeinfo>
The C working draft N1539 section 4 paragraph 6 requires freestanding implementations to provide: <float.h> <iso646.h> <limits.h> <stdalign.h> <stdarg.h> <stdbool.h> <stddef.h> <stdint.h>
These two requirements have notable inconsistencies.
*.h
forms of the headers are not required by the C++,
though they are by C.
Taken as a whole, the C specification for freestanding implementations does not require run-time library support: memory allocation, string routines, and input/output. This is in marked contrast to C++, which seems to require more than necessary.
The set of freestanding headers required by C++ should include at least those required by C. Implementors will anyway because few would support only C++, so failing to support those headers simply invites an inconsistency between the standard and practice.
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) 17.6.1.2, C.2.2.3 Named operators <ciso646> <iso646.h>
18.2 Types <cstddef> <stddef.h>
18.3 Implementation properties <cfloat> <float.h> <limits> <climits> <limits.h>
18.4 Integer types <cstdint> <stdint.h>
... ... ... 18.10 Other runtime support <cstdalign> <stdalign.h> <cstdarg> <stdarg.h> <cstdbool> <stdbool.h>
... ... ...
Since freestanding implementations are generally for embedded systems, the requirements should not require significant run-time implementation. The C standards community is generally closer to embedded systems, and the list of C freestanding headers reflects lean implementations. C++ policy should do the same.
In particular, C does not require <stdlib.h> in freestanding implementations because of the run-time overhead embodied in that header. Even though C++ only requires a subset of <stdlib.h>, requiring it would still be a burden on some implementations. Likewise, features requiring dynamic memory allocation or unneeded code size are also often avoided in embedded systems. The headers <exception>, <new>, and <typeinfo> are in this class. They would also be a burden on some implementations. (We recognize that their absence would prevent use of some language features, but such systems already prohibit their use.)
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) ... ... ... 18.5Start and termination<cstdlib>
18.6Dynamic memory management<new>
18.7Type identification<typeinfo>
18.8Exception handling<exception>
... ... ...
Edit paragraph 3 as follows.
The supplied version of the headerThe supplied version of the header<cstdlib>
shall declare at least the functionsabort
,atexit
,at_quick_exit
,exit
, andquick_exit
(18.5).<thread>
shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation.
Atomics are fairly tightly integrated into the language, and are required on any concurrent system. On systems without concurrency, atomics have trivial implementation. So under the above criteria, as suggested by GB 57, should be included in the freestanding headers.
In contrast, <mutex> is more likely to be implemented in freestanding implementations than is <thread> and yet their freestanding requirements are opposite. Furthermore, there are many single-threaded embedded systems. So, <thread> should not be required of freestanding implementations. Consequently, <ratio> and <chrono> would not need to be freestanding and GB 55 would become moot.
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) ... ... ... 29 Atomics <atomic>
30.3Threads<thread>
Edit paragraph 3 as follows.
The supplied version of the header
<cstdlib>
shall declare at least the functionsabort
,atexit
,at_quick_exit
,exit
, andquick_exit
(18.5).The supplied version of the headerThe other headers listed in this table shall meet the same requirements as for a hosted implementation.<thread>
shall meet the same requirements as for a hosted implementation or including it shall have no effect.
C++ is necessarily a larger language than C, and the line between the language and the library is fuzzier. C++ should be willing and able to incorporate headers into freestanding implementations when the need is apparent and the run-time implementation is small.
As an example, rvalue references are very difficult to use without (at least replicating) some of the facilities defined in <utility>. Their implementation is tiny. So, GB 56 should be reconsidered. At a minimum, the move, forward, swap, and declval functions should be split into a separate header.
Table 14 — C++ library headers .... <future>
<helpers>
<initializer_list>
....
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) ... ... ... 20.? Helper components <helpers>
20.7 Type traits <type_traits>
... ... ...
Create a new section "Helper components" before 20.3 Utility components [utility].
Add a paragraph 1.
This subclause contains some basic function and class templates that are used throughout the rest of the library.
Add a synopsis.
- Header
<helpers>
synopsisnamespace std { // 20.?.1, swap: template<class T> void swap(T& a, T& b) noexcept(see below); template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))); // 20.?.2, forward/move: template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept; template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept; template <class T> typename remove_reference<T>::type&& move(T&&) noexcept; template <class T> typename conditional< !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value, const T&, T&&>::type move_if_noexcept(T& x) noexcept; // 20.?.3, declval: template <class T> typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand }
Move the entire subsubclause 20.3.2 into the new subclause above.
Move the entire subsubclause 20.3.3 into the new subclause above.
declval
[declval]Move the entire subsubclause 20.3.4 into the new subclause above.
Edit the synopsis as follows.
- Header
<utility>
synopsis#include <initializer_list> #include <helpers> namespace std { ....
// 20.3.2, swap: template<class T> void swap(T& a, T& b) noexcept(see below); template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));// 20.3.3, forward/move: template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept; template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept; template <class T> typename remove_reference<T>::type&& move(T&&) noexcept; template <class T> typename conditional< !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value, const T&, T&&>::type move_if_noexcept(T& x) noexcept;// 20.3.4, declval: template <class T> typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand....
As an alternative to the change above, we could do all that GB 56 requests.
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) ... ... ... 20.3 Utility components <utility>
20.4 Tuples <tuple>
20.7 Type traits <type_traits>
... ... ...
C++ has no defined mechanism for indicating conditional features. As a consequence, this aspects of the standard is incomplete and inconsistent.
__STDCPP_STRICT_POINTER_SAFETY__
- Defined, and has the value integer constant 1, if and only if the implementation has strict pointer safety (3.7.4.3 [basic.stc.dynamic.safety]).
The C working draft N1539 section 6.10.8.3 paragraph 1 requires conditionally macros indicating (lack of) support for conditional features.
(Note that there are NB comments on C1x against the current formulation of __STDC_NO_THREADS__.)
In constrast, The C++ working draft N3225 generally ignores conditional behavior, except that the <thread> header either defines _STDCPP_THREADS__ and the full set of symbols, or has no effect. This mechanism is different from that of C, and more difficult to use.
Most programmers will not write code that adapts to the presence or absence of conditional features. As a consequence, the use of a missing feature should be transparently obvious. Therefore, if a feature is missing, the C++ implementation should simply not provide the corresponding header. The error message will be brutally obvious — header not found.
In C++ 2003, there are no macros indicating C++ conditional features. We could as well do the same thing in C++0x, which would serve the vast majority of programmers.
Therefore, we should remove the __STDCPP_THREADS__ macro from <thread>.
Edit paragraph 3 as follows.
The supplied version of the header
<cstdlib>
shall declare at least the functionsabort
,atexit
,at_quick_exit
,exit
, andquick_exit
(18.5).The supplied version of the headerThe other headers listed in this table shall meet the same requirements as for a hosted implementation.<thread>
shall meet the same requirements as for a hosted implementation or including it shall have no effect.
Edit the synopsis as follows.
namespace std {
#define __STDCPP_THREADS__ __cplusplus....
Some programmers can and would will write code that adapts to the presence or absence of conditional features, if a language mechanism were available.
C uses predefined macros to indicate conditional features. C++ could do the same.
C uses a mix of positive and negative sense macros. C++ defines mostly positive macros in 16.8 [cpp.predefined]. As postive sense macros are easier to reason with, we should use them.
So, we should add a predefined __STDCPP_THREADS__ macro.
As it is somewhat likely that other thread-related headers will be implemented or not in concert with <thread>, we should make those headers conditional under the same macro.
Add the following to the end of paragraph 2.
__STDCPP_THREAD__
- Defined, and has the value integer constant 1, if and only if the implementation provides the headers <condition_variable> (30.5 [thread.condition]), <future> (30.6 [futures]), <mutex> (30.4 [thread.mutex]), and <thread> (30.3 [thread.threads]).
As an alternative to the approach above, we can provide a library header that provides the macros indicating whether or not a header is present, as suggested in the proposed resolution to LWG 1358. This approach has the virtue of moving indications of library features to the library implementation. Its cost is that library implementations must provide another header and programmers testing conditional features would need to include that header.
Table 14 — C++ library headers .... <iterator>
<library_support>
<limits>
....
Edit table 16 as follows.
Table 16 — C++ headers for freestanding implementations Subclause Header(s) ... ... ... 20.? Library header support <library_support>
20.7 Type traits <type_traits>
... ... ...
Edit paragraph 3 as follows.
The supplied version of the header
<cstdlib>
shall declare at least the functionsabort
,atexit
,at_quick_exit
,exit
, andquick_exit
(18.5).The supplied version of the header. The other headers listed in this table shall meet the same requirements as for a hosted implementation. A program can detect the presence of standard headers not listed in Table 16 using the facilities provided by the<thread>
shall meet the same requirements as for a hosted implementation or including it shall have no effect<library_support>
header.
Add a new section in Clause 18.
Add a new paragraph as follows.
The header
<library_support>
defines an implementation-defined set of macros to enable a program detect the presence of standard headers in freestanding implementations. [Note: Hosted implementations shall provide all standard headers, thus shall provide all macros. —end note]
Add a new paragraph as follows.
For each standard header listed in Tables 14 (C++ library headers) and 15 (C++ headers for C library facilities) that is provided by the implementation,
<library_support>
shall define a macro with name__STDCPP_HAS_XXX_HEADER__
whereXXX
is replaced by the uppercase version of the name of the header. Each such macro shall expand to the value__cplusplus
.
Add a new paragraph as follows.
[Example:
#include <library_support> #ifdef __STDCPP_HAS_THREAD_HEADER__ #include <thread> // code that exploit the presence of threads #else // fallback code that doesn't rely on threads #endif
—end example]
Add a new paragraph as follows.
No other standard header shall define macros with a name beginning with
__STDCPP_HAS_
and ending with_HEADER__
.