dxx-rebirth/Documentation/c++std.markdown

9.3 KiB

Required C++11 features

DXX-Rebirth code uses C++11 features present in >=clang-3.4 and >=gcc-4.7. Some of these features are probed in the SConf tests so that an error can be reported if the feature is missing. However, since these are considered the minimum supported compiler versions, and existing SConf tests reject gcc-4.6, some C++11 features that are new in gcc-4.7 may be used without a corresponding test in SConf.

These C++11 features are required to build DXX-Rebirth:

Optional C++11/C++14 features

DXX-Rebirth code uses C++11 or C++14 features not present in the minimum supported compiler if the feature can be emulated easily (C++11: inheriting constructors, Range-based for ;C++14: std::exchange, std::index_sequence, std::make_unique) or if the feature can be removed by a macro and the removal does not change the correctness of the program (C++11: rvalue-qualified member methods).

Optional C++11 features

Emulated if absent

  • Inheriting constructors are wrapped by the macro DXX_INHERIT_CONSTRUCTORS. If inherited constructors are supported, then DXX_INHERIT_CONSTRUCTORS expands to a using declaration. If inherited constructors are not supported, then DXX_INHERIT_CONSTRUCTORS defines a variadic template constructor to forward arguments to the base class.
  • Range-based for is wrapped by the macro range_for. This feature is present in the current minimum supported compiler versions. It was first used when >=gcc-4.5 was the minimum. Use of the range_for macro continues because it improves readability.

Preprocessed out if absent

  • Static assertions check that a compile-time constant expressions evaluates to true. Static assertions are fully supported in >=gcc-4.7. Static assertions are partially supported in >=clang-3.4. Some complicated compile-time expressions are accepted by gcc, but are not considered as compile-time constant by clang. SConf checks whether the active compiler accepts such expressions and replaces static_assert() with a no-op macro if the compiler cannot handle them.
    • As a consequence of the macro replacement, calls to static_assert must have two arguments as viewed by the C preprocessor. When the truth argument has internal commas, the entire truth expression must be wrapped in parentheses to protect it from the preprocessor.
  • Reference-qualified methods check that an rvalue which may or may not hold a valid pointer is not used in a context where the caller assumes the rvalue holds a valid pointer. When the rvalue may or may not hold a valid pointer, it must be saved to an lvalue, tested for a valid pointer, and used only if a valid pointer is found. The preprocessor symbol DXX_HAVE_CXX11_REF_QUALIFIER is defined if reference-qualified methods are available. Code which defines reference-qualified methods must be guarded with #ifdef DXX_HAVE_CXX11_REF_QUALIFIER.

Optional C++14 features

  • std::exchange is a convenience utility function. If std::exchange is available, then common/include/compiler-exchange.h uses using std::exchange; to bring exchange into the global namespace. If std::exchange is not available, then common/include/compiler-exchange.h provides a simple implementation of exchange in the global namespace.

  • std::index_sequence is a compile-time sequence of integers. If std::index_sequence is available, then common/include/compiler-integer_sequence.h uses using std::index_sequence; to bring index_sequence into the global namespace. If std::index_sequence is not available, then common/include/compiler-integer_sequence.h provides a simple implementation of index_sequence in the global namespace. The simple implementation lacks standards-required features, but is sufficient for current Rebirth code. The simple implementation may be extended to support standards-required features if a need exists.

    Regardless of whether std::index_sequence is available, common/include/compiler-integer_sequence.h provides ::make_tree_index_sequence, which is functionally equivalent to std::make_index_sequence, but generates sequences with shallower template recursion than gcc's std::make_index_sequence. Sequences longer than the maximum template recursion depth cannot be generated using gcc's std::make_index_sequence, but can be generated by ::make_tree_index_sequence. ::make_tree_index_sequence is still limited by the maximum template recursion depth, but can generate much deeper sequences before the recursion limit is triggered. Given enough CPU time and swap space, ::make_tree_index_sequence can instantiate a 10000000 element index_sequence when the maximum template depth is 900. With enough patience and resources, higher values are likely possible. However, even 10000000 produced very long compile times.

    See gcc bug #66059: make_integer_sequence should use a log(N) implementation for the enhancement request to provide a library implementation with similar scaling ability.

  • std::make_unique is a convenience utility function. If std::make_unique is available, then common/include/compiler-make_unique.h uses using std::make_unique; to bring make_unique into the global namespace. If std::make_unique is not available, then common/include/compiler-make_unique.h provides a simple implementation of make_unique in the global namespace.