Expand description
The C++ CST as the other end of a rule. Spec §3.2.
The counterpart of crate::adapter::c, function for function.
Reading the two side by side is the point: where they differ, the
difference is C++’s, and it is written down here rather than spread
through a renderer.
Values are resolved from the model, never from the overlay — the same rule the Rust and the C materialiser follow and for the same reason (spec §2.3).
§The four things C++ gives back that C does not
- Generics, so most structural typedefs disappear. C has to
declare a named
zd_seq_int32_tbecause it cannot write an anonymous aggregate twice and have the two be one type;std::vector<std::int32_t>is that type wherever it is written. The whole of the C column’s structural-name machinery — thezd_seq_,zd_arr_,zd_map_declarations and the collision hazard that came with them — is gone from the output. It is not gone from the naming: seecpp_type_tag. - Namespaces, so a module is a scope and not a prefix. C
flattens
a::b::Footoa_b_Foo; here the IDL scoping survives asnamespace a { namespace b { struct Foo … } }, and every reference to a declared type is written from the root —::a::b::Foo— so a member never depends on which namespace it is read in. - An enumeration wide enough. A C enumeration constant is an
int(C11 §6.7.2.2), which is why the C column emits a fixed-width typedef and a run of#defines. C++11’s scoped enumeration takes an explicit underlying type, so@bit_bound(32)— which admits enumerator values up to2^32 - 1— can be held by the type itself. This is the one place C++ is simpler. - A plain pointer for an absent member. The C column writes a
T *and a NULL for an@optionalmember, and so does this one: DDS-XTypes 1.3 §7.5.1.2.4.2 asks for “plain pointers rather than automatic values or smart pointers”, NULL for an omitted value. The class owns what the pointer points at — the destructor deletes it, a copy is deep (§7.5.1.2.3.2, “the same as specified for C”) — and the member functions that say so are generated beside the members (owning_members).
§The memory shapes
| IDL | C++ |
|---|---|
string | std::string |
wstring | std::string, holding UTF-8 |
fixed<P,S> | std::string, holding the decimal |
long double | zerodds::wire::Float128 |
sequence<T> | std::vector<T> |
T a[2][3] | std::array<std::array<T, 3>, 2> |
map<K,V> | zerodds::Map<K, V>, a std::vector<std::pair<K, V>> with the operations of Table 47 |
union | a class with _d() and one accessor per case (IDL4 to C++ 1.0) over a discriminator and one storage per case |
@optional T m | T *m, NULL when absent |
A wstring holds UTF-8 rather than char16_t units for the reason
the C column gives: it puts the §7.4.1.1.2 conversion — the surrogate
rule the byte count depends on — inside runtime/cpp, where it is a
second implementation of the clause and not a copy of the Rust one’s
answer.
A map<K,V> is zerodds::Map — XTypes 1.3
§7.5.1.3.3, a class with the operations of Table 47 — over a vector of
pairs and not a std::map. The order a map’s entries go on the wire
is a policy axis — zerodds_ast_layout::MapEntryOrder, declaration
order against ascending key — and std::map would impose its own
ordering on every dialect before the encoder ever saw the value. A
container that cannot hold declaration order cannot reproduce the four
implementations that write it. The Modern C++ binding of §7.5.1.3.4,
std::map, is CppMapping::Psm.
§Where the IDL spelling of a member is kept
cxx_name moves a colliding name (§7.11.1.1.2 rule 8) — long static;
becomes std::int32_t cxx_static; — and C++ has more keywords to
collide with than C, so it moves more names. XTypes 1.3 §7.3.1.2.1.1
computes a member’s ID under @autoid(HASH) and under @hashid
from the first four octets of the MD5 of its IDL name, so a
header that only knows cxx_static cannot compute the ID for static
and the member it writes lands under an ID the peer does not have.
Every declaration with named parts carries them beside itself, in IDL declaration order — the order the member IDs are assigned in:
inline constexpr std::array<std::pair<const char*, const char*>, 2>
Sample_idl_names = {{{"impl", "impl"}, {"cxx_static", "static"}}};An inline constexpr variable and not the C column’s macro, and
for the reason the constants above are one too: C reaches for the
preprocessor because an object in a header is a separate object in
every translation unit that includes it, and C++17’s inline variable
is one object across the program. So the mapping can be a typed name
— iterable with .size(), usable in a constexpr context, and
reachable as ::a::b::Sample_idl_names from anywhere — where the C
column has to hand a caller a brace-enclosed initialiser and let it
declare the array itself. Measured unused, under
-std=c++20 -Wall -Wextra -Werror, across all 376 headers the
corpus renders: no diagnostic.
std::pair and not a generated record type: a record would be a
declaration whose name could collide with an IDL type, in a header
that has no other reason to declare one, and <utility> is already
in includes.
A union is a class, not a union and not a std::variant. Two
cases may carry the same type — the corpus has such types — and a
std::variant<T, T> cannot say which of the two is live without an
index the discriminator already is. The class has the accessor
functions of IDL4 to C++ 1.0 §7.5.1.4 (_d(), and per case a getter, a
reference getter and two setters, a setter selecting its case) over
one storage member per case and one for the discriminator, which is
the C column’s _d plus _u with the anonymous union opened out; the
generated codec reads and writes the storage (zd_d, zd_<case>). A
data member is never warned about for being unused, so this compiles
under -Wall -Wextra -Werror.
Structs§
- CppMapping
Scope - Selects the C++ mapping on the current thread until dropped.
Enums§
- CppMapping
- How the C++ column spells topic types.
- Held
- How the native C++ mapping holds one member.
Constants§
- FLOA
T128 - The C++ spelling of
long double. - NATIVE_
NAMESPACE - The namespace the native types stand in under
CppMapping::Psm.
Functions§
- cpp_
holder - The unsigned integer a bit width calls for.
- cpp_
items - Build the C++ declarations a rule application produced.
- cpp_
mapping - The mapping selected on this thread.
- cpp_
primitive - The C++ type an IDL primitive becomes.
- cpp_
type_ path - The rooted path a reference to a declared type is written as.
- cpp_
type_ tag - The name component a collection or a codec function takes from a type.
- cpp_
value_ type - The C++ type a value of
idis held in. - cxx_
name - The name a module or a type declared in IDL has in C++: the identifier,
or
cxx_in front of it where it is a C++ reserved word. DDS-RPC 1.0 §7.11.1.1.2 rule 8: “Any identifier (e.g., parameter, operation name, exception, interface, module) in an IDL file that is a reserved word in C++ shall be prefixed by “cxx_”.“ - flattened
- A named type’s scoped name with the separators flattened onto it.
- held
Heldformember.- includes
- The headers a materialised translation unit needs.
- nest_
by_ module - The declarations, each inside the
namespaceits IDL module names. - nest_
by_ module_ placed - As
nest_by_module, for declarations of the two kindsCppMapping::Psmtells apart:nativeones stand inNATIVE_NAMESPACE, the others in the namespaces of the IDL.