sim_cpp11_features.pl¶
Purpose¶
The sim_cpp11_features.pl program converts a file with specially
delimited regions of C++11 code and generates a C++03 version of that code that
emulates the C++11 features. By default, the C++03 expansions are placed in a
separate file with an extra “_cpp03
” delimiter before the extension.
Currently, this program emulates two constructs:
Variadic templates (a.k.a. parameter packs) are emulated by creating multiple copies of the template code, starting with zero template arguments and adding an argument with each repetition (up to 10 arguments by default).
Forwarding references in function arguments are emulated by surrounding the argument declaration in a
BSLS_COMPILERFEATURES_FORWARD_REF
macro invocation and replacingstd::forward
calls withBSLS_COMPILERFEATURES_FORWARD
.
Both emulations are approximate, at best, but experience has found them to be extremely useful.
The program is located in the bde-tools
repo as
BdeBuildSystem/scripts/sim_cpp11_features.pl
and is intended to be invoked
by the BBS build system.
Usage¶
Usage: sim_cpp11_features.pl
[ option… ] input-file-name…
Each input file can contain zero or more regions delimited by the simulation marker
#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
and its matching #endif
.
A C++11 compiler will see the code within each simulation region verbetim. A C++03 compiler will see an altenative version of the code generated by this tool.
Options¶
--output=
filename.ext¶
Specifies the name of the output file. By default, the C++11 output overwrites
the input file and the C++03 output is written to a file whose name is the same
as the input filename except with a “_cpp03
” inserted before the filename
extension. For example, if the input file is “bxxy_useful.h
”, then the
C++03 expansion is written to “bxxy_useful_cpp03.h
”. If --output
is
specified, then the C++11 output is written to filename.ext and the C++03
output is written to filename_cpp03.ext. If filename is a single dash (-),
then output is written to standard out (--inplace
mode only).
--[no-]inplace
¶
The --inplace
option causes the C++11 and C++03 code to be intermixed
within the same output file, separated by conditional compilation directives.
This option, which was the only operating mode prior to June 2020, tends to
produce a verbose source file that is difficult to maintain. The default is
--no-inplace
.
--verify-no-change
¶
Verify that nothing has changed in the main file that would result in a change in generated code (including any generated code within the main file itself). If any output (including the main file) would change, do not write any output and abort with an error.
--clean
¶
When used with --inplace
, removes all C++03 emulation code, leaving a
C++11-only file that is more convenient to maintain during development.
Typically, this option is used once just before adding or modifying code. After
a successful build using C++11, this tool is typically run again without
--clean
to produce release code that can be tested with C++03.
--var-args=
max-args¶
The maximum number of variadic template expansions to generate (default 10). This value is written into the C++11 file as an embedded option (see below) so that future runs do not need to specify this option again.
--test
¶
Runs the tool on a built-in test file, producing a diff
of the original
and modified file if changes were detected. Usually used with --inplace
.
--debug=
level¶
Turns on debugging at the specified level. The higher the level, the more verbose the output.
--trace=
subroutine:level¶
Turns on tracing for the specified subroutine (for debugging).
input-file-name…¶
One or more input file names. If the input file is a single dash (-), then read from standard input.
Embedded options¶
A few options can be embedded directly into the input file at the end of an
#if
directive that introduces a region to be emulated:
// $var-args=
n¶
Globally sets the maximum number of variadic template expansions to n . A
value specified using the command-line --var-args
option overrides the
value of n specified using this embedded option and overwrites n in the
generated output.
// $local-var-args=
n¶
Sets the maximum number of variadic template expansions to n only for the
current region. The number of expansions returns to the file default after the
closing #endif
.
Limitations¶
The C++11 emulation provided by this tool is incomplete at best. It does not produce a semantic interpretation of the input code and is limited to basic pattern matching. Known limitations are:
All parameter packs for a given instantiation of a variadic template must be the same length.
Perfect-forwarding emulation does not recognize prvalues as rvalues.
There is limited support for partial specialization of variadic class templates. In particular, specializing on the empty parameter pack is not currently supported.
Example¶
The following input file (let’s call it “foo.h
”):
#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=3
template <class... ARG>
void j(ARG&&... arg) {
g(std::forward<ARG>(arg)...);
}
#endif
gets rewritten into the same input file (“foo.h
”) as:
#include <bsls_compilerfeatures.h>
#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// Include version that can be compiled with C++03
// Generated on Mon Nov 2 13:17:20 2020
// Command line: sim_cpp11_features.pl foo.h
# define COMPILING_FOO_H
# include <foo_cpp03.h>
# undef COMPILING_FOO_H
#else
#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=3
template <class... ARG>
void j(ARG&&... arg) {
g(std::forward<ARG>(arg)...);
}
#endif
#endif // End C++11 code
and a new “_cpp03
” header file is created with the C++03 equivalent
expansions (“foo_cpp03.h
”):
// foo_cpp03.h -*-C++-*-
// Automatically generated file. **DO NOT EDIT**
#ifndef INCLUDED_FOO_CPP03
#define INCLUDED_FOO_CPP03
//@PURPOSE: Provide C++03 implementation for foo.h
//
//@CLASSES: See foo.h for list of classes
//
//@SEE_ALSO: foo
//
//@DESCRIPTION: This component is the C++03 translation of a C++11 component,
// generated by the 'sim_cpp11_features.pl' program. If the original header
// contains any specially delimited regions of C++11 code, then this
// generated file contains the C++03 equivalent, i.e., with variadic templates
// expanded and rvalue-references replaced by 'bslmf::MovableRef' objects.
// The header code in this file is designed to be '#include'd into the
// original header when compiling with a C++03 compiler. If there are no
// specially delimited regions of C++11 code, then this header contains no
// code and is not '#include'd in the original header.
//
// Generated on Mon Nov 2 13:17:20 2020
// Command line: sim_cpp11_features.pl foo.h
#ifdef COMPILING_FOO_H
#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl foo.h
#ifndef FOO_VARIADIC_LIMIT
#define FOO_VARIADIC_LIMIT 3
#endif
#ifndef FOO_VARIADIC_LIMIT_A
#define FOO_VARIADIC_LIMIT_A FOO_VARIADIC_LIMIT
#endif
#if FOO_VARIADIC_LIMIT_A >= 0
void j() {
g();
}
#endif // FOO_VARIADIC_LIMIT_A >= 0
#if FOO_VARIADIC_LIMIT_A >= 1
template <class ARG_1>
void j(BSLS_COMPILERFEATURES_FORWARD_REF(ARG_1) arg_1) {
g(BSLS_COMPILERFEATURES_FORWARD(ARG_1, arg_1));
}
#endif // FOO_VARIADIC_LIMIT_A >= 1
#if FOO_VARIADIC_LIMIT_A >= 2
template <class ARG_1,
class ARG_2>
void j(BSLS_COMPILERFEATURES_FORWARD_REF(ARG_1) arg_1,
BSLS_COMPILERFEATURES_FORWARD_REF(ARG_2) arg_2) {
g(BSLS_COMPILERFEATURES_FORWARD(ARG_1, arg_1),
BSLS_COMPILERFEATURES_FORWARD(ARG_2, arg_2));
}
#endif // FOO_VARIADIC_LIMIT_A >= 2
#if FOO_VARIADIC_LIMIT_A >= 3
template <class ARG_1,
class ARG_2,
class ARG_3>
void j(BSLS_COMPILERFEATURES_FORWARD_REF(ARG_1) arg_1,
BSLS_COMPILERFEATURES_FORWARD_REF(ARG_2) arg_2,
BSLS_COMPILERFEATURES_FORWARD_REF(ARG_3) arg_3) {
g(BSLS_COMPILERFEATURES_FORWARD(ARG_1, arg_1),
BSLS_COMPILERFEATURES_FORWARD(ARG_2, arg_2),
BSLS_COMPILERFEATURES_FORWARD(ARG_3, arg_3));
}
#endif // FOO_VARIADIC_LIMIT_A >= 3
#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
template <class... ARG>
void j(BSLS_COMPILERFEATURES_FORWARD_REF(ARG)... arg) {
g(BSLS_COMPILERFEATURES_FORWARD(ARG, arg)...);
}
// }}} END GENERATED CODE
#endif
#else // if ! defined(DEFINED_FOO_H)
# error Not valid except when included from foo.h
#endif // ! defined(COMPILING_FOO_H)
#endif // ! defined(INCLUDED_FOO_CPP03)
// ----------------------------------------------------------------------------
// Copyright 2020 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------