Skip to main content

Module cpp

Module cpp 

Source
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

  1. Generics, so most structural typedefs disappear. C has to declare a named zd_seq_int32_t because 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 — the zd_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: see cpp_type_tag.
  2. Namespaces, so a module is a scope and not a prefix. C flattens a::b::Foo to a_b_Foo; here the IDL scoping survives as namespace 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.
  3. 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 to 2^32 - 1 — can be held by the type itself. This is the one place C++ is simpler.
  4. A plain pointer for an absent member. The C column writes a T * and a NULL for an @optional member, 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

IDLC++
stringstd::string
wstringstd::string, holding UTF-8
fixed<P,S>std::string, holding the decimal
long doublezerodds::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
uniona class with _d() and one accessor per case (IDL4 to C++ 1.0) over a discriminator and one storage per case
@optional T mT *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§

CppMappingScope
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§

FLOAT128
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 id is 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
Held for member.
includes
The headers a materialised translation unit needs.
nest_by_module
The declarations, each inside the namespace its IDL module names.
nest_by_module_placed
As nest_by_module, for declarations of the two kinds CppMapping::Psm tells apart: native ones stand in NATIVE_NAMESPACE, the others in the namespaces of the IDL.