-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsd6.tmpl
578 lines (484 loc) · 19.9 KB
/
sd6.tmpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
{% macro make_table(var, is_attr, use_headers) %}
<table>
<tr>
<th>Macro</th>
{% if use_headers %}
<th>Header(s)</th>
{% endif %}
<th>Value</th>
<th>Paper(s)</th>
</tr>
{% for macro in var | sort(attribute='name') %}
{% set outer_loop = loop %}
<tr
{% if loop.index0 % 2 == 0 %}
style="background-color: #f6f8fa"
{% else %}
style="background-color: white"
{% endif %}
>
<td rowspan="{{ macro.rows | length }}">
{%- if is_attr -%}
{% set text = "__has_cpp_attribute(" ~ macro.name ~ ")" %}
{%- else -%}
{% set text = macro.name %}
{%- endif -%}
<span id="{{macro.name}}"><a href="#{{macro.name}}" style="text-decoration:none">`{{text}}`</a></span>
</td>
{%- if use_headers -%}
<td rowspan="{{ macro.rows | length }}">
{%- if 'header_list' in macro -%}
{%- for header in macro.header_list.split() | sort %}
`<{{header}}>`{% endfor -%}
{%- elif 'header_info' in macro -%}
{{macro.header_info}}
{%- endif -%}
</td>
{%- endif -%}
{% for elem in macro.rows | sort(attribute='value') %}
{% set val = elem.value %}
{% if elem.get('removed') %}
<td>[deleted]{.rm}</td>
{% else %}
<td>`{{ val }}`</td>
{% endif %}
<td> {% for paper in elem.get('papers', '').split() -%}
[@{{paper}}] {{refs[paper]}}
{{ "<br />" if not loop.last }}
{%- endfor -%} {{ elem['feature'] }}</td>
{% if not loop.last %}
</tr>
<tr
{% if outer_loop.index0 % 2 == 0 %}
style="background-color: #f6f8fa"
{% else %}
style="background-color: white"
{% endif %}
>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
{% endmacro %}
---
title: "Feature-Test Macros and Policies"
document: SD-FeatureTest
date: today
toc: true
toc-depth: 2
---
<style>
code span.er { color: #6f4e37; font-weight: normal; }
</style>
# Explanation and rationale for the approach
The pace of innovation in the standardization of C++ makes long-term
stability of implementations unlikely. Features are added to the language
because programmers want to use those features. Features are added to (the
working draft of) the standard as the features become well-specified. In many
cases a feature is added to an implementation well before or well after the
standard officially introducing it is approved.
This process makes it difficult for programmers who want to use a feature to
know whether it is available in any given implementation. Implementations
rarely leap from one formal revision of the standard directly to the next;
the implementation process generally proceeds by smaller steps. As a result,
testing for a specific revision of the standard (e.g. by examining the value
of the `__cplusplus` macro) often gives the wrong answer. Implementers
generally don't want to appear to be claiming full conformance to a standard
revision until all of its features are implemented. That leaves programmers
with no portable way to determine which features are actually available to
them.
It is often possible for a program to determine, in a manner specific to a
single implementation, what features are supported by that implementation;
but the means are often poorly documented and ad hoc, and sometimes complex –
especially when the availability of a feature is controlled by an invocation
option. To make this determination for a variety of implementations in a
single source base is complex and error-prone.
## Status quo before feature-test macros
Here is some code that attempts to determine whether rvalue references are
available in the implementation in use:
```cpp
#ifndef __USE_RVALUE_REFERENCES
#if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \
_MSC_VER >= 1600
#if __EDG_VERSION__ > 0
#define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410)
#else
#define __USE_RVALUE_REFERENCES 1
#endif
#elif __clang__
#define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
#else
#define __USE_RVALUE_REFERENCES 0
#endif
#endif
```
First, the GNU and Microsoft version numbers are checked to see if they are
high enough. But then a check is made of the EDG version number, since that
front end also has compatibility modes for both those compilers, and defines
macros indicating (claimed) compatibility with them. If the feature wasn’t
implemented in the indicated EDG version, it is assumed that the feature is
not available – even though it is possible for a customer of EDG to implement
a feature before EDG does.
Fortunately Clang has ways to test specifically for the presence of specific
features. But unfortunately, the function-call-like syntax used for such
tests won’t work with a standard preprocessor, so this fine new feature winds
up adding its own flavor of complexity to the mix.
Also note that this code is only the beginning of a real-world solution. A
complete solution would need to take into account more compilers, and also
command-line option settings specific to various compilers.
## Characteristics of the proposed solution
To preserve implementers’ freedom to add features in the order that makes the
most sense for themselves and their customers, implementers should indicate
the availability of each separate feature by adding a definition of a macro
with the name corresponding to that feature.
Important note: By recommending the use of these macros, WG21 is not making
any feature optional; the absence of a definition for the relevant
feature-test macro does not make an implementation that lacks a feature
conform to a standard that requires the feature. However, if implementers and
programmers follow these recommendations, portability of code between
real-world implementations should be improved.
To a first approximation, a feature is identified by the WG21 paper in which
it is specified, and by which it is introduced into the working draft of the
standard. Not every paper introduces a new feature worth a feature-test
macro, but every paper that is not just a collection of issue resolutions is
considered a candidate; exceptions are explicitly justified.
For C++14, the feature-test macro name generally consists of some combination
of words from the title of the paper. In the future, it is hoped that every
paper will include its own recommendations concerning feature-test macro names.
The value specified for a feature-test macro is based on the year and month
in which the feature is voted into the working draft. In a case where a
feature is subsequently changed in a significant way, but arguably remains
the same feature, the value of the macro is changed to indicate the “revision
level” of the specification of the feature. However, in most cases it is
expected that the presence of a feature can be determined by the presence of
any non-zero macro value; for example:
```cpp
template<typename T>
struct use_empty_base_opt :
std::integral_constant<bool,
std::is_empty<T>::value
#if __cpp_lib_is_final
&& !std::is_final<T>::value
#endif
>
{ };
```
To avoid the user’s namespace, names of macros for language features are
prefixed by `__cpp_`; for library features, by `__cpp_lib_`. A library
feature that doesn’t introduce a new header is expected to be defined by the
header(s) that implement the feature.
## Examples
Selecting a more efficient compile-time implementation based on the availability
of a feature:
::: bq
```cpp
#if __cpp_variadic_using
// can use the compile-time efficient, flat inheritance
template<typename ...T> struct Callable : T... {
using T::operator() ...;
};
#else
// fall-back to linear recursion for older compilers
template<typename ...T> struct Callable;
template<typename T, typename ...U>
struct Callable<T, U...> : T, Callable<U...> {
using T::operator();
using Callable<U...>::operator();
};
template<typename T> struct Callable<T> : T {
using T::operator();
};
template<> struct Callable<> {};
#endif
```
:::
Likewise
::: bq
```cpp
#if __cpp_fold_expressions
template<typename... T>
auto sum(T... args) { return (args + ...); }
#else
auto sum() { return 0; }
template<typename T>
auto sum(T t) { return t; }
template(typename T, typename... Ts)
auto sum(T t, Ts... ts) { return t + sum(ts...); }
#endif
```
:::
Selecting a more efficient run-time implementation based on the availability of
a feature:
::: bq
```cpp
void update(std::set<X>& set, const X& elem, int val)
{
auto pos = set.find(elem);
if (pos == set.end())
return;
#if __cpp_lib_node_extract
auto next = std::next(pos);
auto x = set.extract(pos);
x.value().update(val);
set.insert(next, std::move(x));
#else
X tmp = *pos;
pos = set.erase(pos);
tmp.update(val);
set.insert(pos, std::move(tmp));
#endif
}
```
:::
In some cases, the value of a feature-test macro can change over time as the
underlying feature changes. To make it easier to follow the evolution of each
feature, the tables in this document are grouped by macro name -
with a row for each possible value and the proposal(s) associated with it.
Conditionally implementing a feature, based on
[`__cpp_static_assert`](#__cpp_static_assert).
::: bq
```cpp
#if __cpp_static_assert
# if __cpp_static_assert > 201400
# define Static_Assert(cond) static_assert(cond)
# else
# define Static_Assert(cond) static_assert(cond, #cond)
# endif
# define Static_Assert_Msg(cond, msg) static_assert(cond, msg)
#else
# define Static_Assert(cond)
# define Static_Assert_Msg(cond, msg)
#endif
```
:::
Attributes can also change semantics over time,
which is why the `__has_cpp_attribute` facility described below evaluates to a
value rather than simply `1` or `0`. This allows a user to conditionally provide
a version of nodiscard based on [`__has_cpp_attribute(nodiscard)`](#nodiscard):
::: bq
```cpp
#if __has_cpp_attribute(nodiscard) >= 201907
// nodiscard has a reason and can
// be applied to constructors
# define NODISCARD(msg) [[nodiscard(msg)]]
# define NODISCARD_CTOR(msg) [[nodiscard(msg)]]
#elif __has_cpp_attribute(nodiscard) >= 201603
// nodiscard doesn't have a reason, nor can
# define NODISCARD(msg) [[nodiscard]]
# define NODISCARD_CTOR(msg)
#else
// nodiscard doesn't exist at all yet
# define NODISCARD(msg)
# define NODISCARD_CTOR(msg)
#endif
```
:::
# Recommendations
## Introduction
For the sake of improved portability between partial implementations of
various C++ standards, WG21 (the ISO technical committee for the C++
programming language) recommends that implementers and programmers follow the
guidelines in this document concerning feature-test macros.
Implementers who provide a new standard feature should define a macro with
the recommended name and value, in the same circumstances under which the
feature is available (for example, taking into account relevant command-line
options), to indicate the presence of support for that feature.
Programmers who wish to determine whether a feature is available in an
implementation should base that determination on the state of the macro with
the recommended name. (The absence of a tested feature may result in a
program with decreased functionality, or the relevant functionality may be
provided in a different way. A program that strictly depends on support for a
feature can just try to use the feature unconditionally; presumably, on an
implementation lacking necessary support, translation will fail. Therefore,
if the most useful purpose for a feature-test macro would be to control the
inclusion of a #error directive if the feature is unavailable, that is
considered inadequate justification for the macro. Note that the usefulness
of a test macro for a feature is completely independent of the usefulness of
the feature itself.)
## Testing for the presence of a header: `__has_include`
It is impossible for a C++ program to directly, reliably, and portably
determine whether or not a library header is available for inclusion.
Conditionally including a header requires the use of a configuration macro,
whose setting can be determined by a configuration-test process at build time
(reliable, but less portable), or by some other means (often not reliable or
portable).
To solve this general problem, WG21 recommends that programmers use the
`__has_include` feature.
### Syntax
> | _h-preprocessing-token_:
> | any _preprocessing-token_ other than `>`
> |
> | _h-pp-tokens_:
> | _h-preprocessing-token_
> | _h-pp-tokens_ _h-preprocessing-token_
> | _has-include-expression_:
> | `__has_include` `(` _header-name_ `)`
> | `__has_include` `(` _string-literal_ `)`
> | `__has_include` `(` `<` _h-pp-tokens_ `>` `)`
### Semantics
In the first form of the _has-include-expression_, the parenthesized
_header-name_ token is not subject to macro expansion. The second and third
forms are considered only if the first form does not match, and the
preprocessing tokens are processed just as in normal text.
A _has-include-expression_ shall appear only in the controlling constant
expression of a `#if` or `#elif` directive ([cpp.cond] 16.1). Prior to the
evaluation of such an expression, the source file identified by the
parenthesized preprocessing token sequence in each contained
_has-include-expression_ is searched for as if that preprocessing token
sequence were the _pp-tokens_ in a `#include` directive, except that no further
macro expansion is performed. If such a directive would not satisfy the
syntactic requirements of a `#include` directive, the program is ill-formed.
The _has-include-expression_ is replaced by the _pp-number_ `1` if the search
for the source file succeeds, and by the _pp-number_ `0` if the search fails.
The `#ifdef` and `#ifndef` directives, and the defined conditional inclusion
operator, shall treat `__has_include` as if it were the name of a defined
macro. The identifier `__has_include` shall not appear in any context not
mentioned in this section.
### Example
This demonstrates a way to use a library optional facility only if it is
available. Note that having `__has_include(<optional>)` succeed is insufficient
since on many toolchains, headers may exist in installations but have their
contents guarded based on compile flags. For example, the following:
```cpp
#ifdef __has_include
#if __has_include(<optional>)
#include <optional>
std::optional<int> o;
#endif
#endif
int main(){ }
```
will still fail to compile with `g++ -std=c++14` (using libstdc++).
Hence, we need to do:
```cpp
#ifdef __has_include
# if __has_include(<optional>)
# include <optional>
# if __cpp_lib_optional >= 201606
# define have_optional 1
# endif
# elif __has_include(<experimental/optional>)
# include <experimental/optional>
# if __cpp_lib_experimental_optional >= 201400
# define have_optional 1
# define experimental_optional 1
# endif
#endif
#ifndef have_optional
# define have_optional 0
#endif
```
Additionally, the `<version>` header [@P0754R2] is a light-weight header that
defines all the standard library feature-test macros.
An alternate implementation could be:
```cpp
#ifndef __has_include
# define __has_include(x) 0
#endif
#if __has_include(<version>)
# include <version>
#elif __has_include(<optional>)
# include <optional>
#endif
#if __cpp_lib_optional >= 201606
# define have_optional 1
#else
# define have_optional 0
#endif
```
## Testing for the presence of an attribute: `__has_cpp_attribute`
A C++ program cannot directly, reliably, and portably determine whether or
not a standard or vendor-specific attribute is available for use. Testing for
attribute support generally requires complex macro logic, as illustrated
above for language features in general.
To solve this general problem, WG21 recommends that programmers use the
`__has_cpp_attribute` feature.
### Syntax
> | _has-attribute-expression_:
> | `__has_cpp_attribute` `(` _attribute-token_ `)`
### Semantics
A _has-attribute-expression_ shall appear only in the controlling constant
expression of a `#if` or `#elif` directive ([cpp.cond] 16.1). The
_has-attribute-expression_ is replaced by a _non-zero_ _pp-number_ if the
implementation supports an attribute with the specified name, and by the
_pp-number_ `0` otherwise.
For a standard attribute, the value of the `__has_cpp_attribute` macro is
based on the year and month in which the attribute was voted into the working
draft. In the case where the attribute is vendor-specific, the value is
implementation-defined. However, in most cases it is expected that the
availability of an attribute can be detected by any non-zero result.
The `#ifdef` and `#ifndef` directives, and the defined conditional inclusion
operator, shall treat `__has_cpp_attribute` as if it were the name of a defined
macro. The identifier `__has_cpp_attribute` shall not appear in any context not
mentioned in this section.
### Example
This demonstrates a way to use the attribute `[[deprecated]]` only if it is
available.
```cpp
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(deprecated)
# define ATTR_DEPRECATED(msg) [[deprecated(msg)]]
#else
# define ATTR_DEPRECATED(msg)
#endif
```
# Policies
SG-10 has adopted a number of policies related to our standard practices for
determining and naming macros.
## `constexpr`
For the language, we will have a single `__cpp_constexpr` macro. It will be
bumped every time we extend constexpr in the language. For the library, we will
add a specific feature-test macros for significant, special features.
Otherwise, for those cases where we are just adding constexpr to more things in
the library, we will have a dedicated test macro per header and just bump that
header-specific macro on each change. That macro will be named
`__cpp_lib_constexpr_HEADER` (with the exception of a few preexisting macros for
array and algorithm which have slightly different names).
From [@P1902R1].
## Language Features with Library Components
In some cases a feature requires two macros, one for the language and one for
the library. For example, the library does not want to define its three-way
comparison operations unless the compiler supports the feature.
For end-users, it is suggested that they test only the library macro, as that
will only be true if the language macro is also true. As a result, the language
macros contain "`impl`" to distinguish them from the more general version that
is expected to be set by the library.
Note that originally SG10 suggested that the library version of the macro not
include the usual `_lib` part, but LWG was not comfortable with the inconsistency
of having a library macro (which requires a header before it can be used) that
does not contain `_lib`.
Also note that SG10 originally proposed that the core feature tests include
`_lang`, but LWG wanted something that more clearly implied that the the macro
was for a core feature and not intended to be used by end-users. They
sugggested that `_impl` be used instead.
From [@P1353R0].
# Table of Feature-Test Macros
The following are all the feature-test macros in the standard, broken up by
language macros, attribute macros, and library macros, then sorted by name. Each
macro will contain its list of possible values and the papers necessary to be
implemented before an implementation should define that macro with that
particular value.
Note that a given paper may introduce or update multiple feature-test macros. A
given value may require multiple papers. A paper may also _remove_ a
feature-test macro, in which case its value will be specified as
[deleted]{.rm}.
## Language Feature-Test Macros
All of the language macros are predefined (i.e. no header needs to be included
before doing checks).
In some cases, a feature requires two macros: one for the language and one
for the library. For example, the library does not want to define its
three-way comparison operators unless the compiler supports the feature. In
these cases, it is suggested for end-users that they only test the library
macro. Those core language feature-test macros that are intended to be
checked by the library are spelled `__cpp_impl_*`.
{{ make_table(lang_macros, False, False) }}
## Attribute Feature-Test Macros
All of the following macros are predefined.
{{ make_table(attr_macros, True, False) }}
## Library Feature-Test Macros
All of the following macros are defined after inclusion of the header
`<version>` or one of the corresponding headers specified below.
{{ make_table(lib_macros, False, True) }}