Quick reference
Here's how to recognize if a particular type/function/identifier in C++ code is part of the new C++ bindings or high-level C++ bindings.
Taking the examples.keyvaluestore.baseline library as example:
library examples.keyvaluestore.baseline;
type Item = struct {
    key string:128;
    value vector<byte>:64000;
};
type WriteError = flexible enum {
    UNKNOWN = 0;
    INVALID_KEY = 1;
    INVALID_VALUE = 2;
    ALREADY_EXISTS = 3;
};
@discoverable
open protocol Store {
    /// Writes an item to the store.
    flexible WriteItem(struct {
        attempt Item;
    }) -> () error WriteError;
};
Here are how the various FIDL elements will map to in the C++ bindings. Note that in the table "C++" refers to the new C++ bindings, and applies equally to both natural domain objects and wire domain objects. "Natural" refers to the natural domain objects in the new C++ bindings. "Wire" refers to the wire domain objects in the new C++ bindings.
| FIDL element | C++ natural types | Comments | |
|---|---|---|---|
| Header include | C++ | #include <fidl/examples.keyvaluestore.baseline/cpp/fidl.h> | Format is `fidl/library name/cpp/fidl.h` | 
| HLCPP | #include <examples/keyvaluestore/baseline/cpp/fidl.h> | Format is `slash separated library name/cpp/fidl.h` | |
| The library | C++ | ::examples_keyvaluestore_baseline | New C++ uses a single level namespace. HLCPP uses nested namespaces. | 
| HLCPP | ::examples::keyvaluestore::baseline | ||
| Item struct | Natural | ::examples_keyvaluestore_baseline::Item | On top of the namespace differences, the wire types are nested under "::wire". | 
| Wire | ::examples_keyvaluestore_baseline::wire::Item | ||
| HLCPP | ::examples::keyvaluestore::baseline::Item | ||
| WriteError enum | Natural | ::examples_keyvaluestore_baseline::WriteError | On top of the namespace differences, the wire types are nested under "::wire". In case of enums and bits, the wire types and natural types are equivalent. There is just an extra type alias. | 
| Wire | ::examples_keyvaluestore_baseline::wire::WriteError | ||
| HLCPP | ::examples::keyvaluestore::baseline::WriteError | ||
| string:128 | Natural | std::string | |
| Wire | fidl::StringView | ||
| HLCPP | std::string | ||
| vector<byte>:64000 | Natural | std::vector<uint8_t> | |
| Wire | fidl::VectorView<uint8_t> | ||
| HLCPP | std::vector<uint8_t> | ||
| protocol Store | C++ | ::examples_keyvaluestore_baseline::Store | A marker type that carries some information about the protocol | 
| HLCPP | ::examples::keyvaluestore::baseline::Store | An abstract base class that contains methods in the protocol | |
| client_end:Store | C++ | fidl::ClientEnd<Store> | |
| HLCPP | fidl::InterfaceHandle<Store> | ||
| server_end:Store | C++ | fidl::ServerEnd<Store> | |
| HLCPP | fidl::InterfaceRequest<Store> | ||
| Client and server types for the Store protocol | Natural | Client: fidl::Client<Store> Synchronous client: fidl::SyncClient<Store> Server interface: fidl::Server<Store> Event handler interface: fidl::EventHandler<Store> | |
| Wire | Client: fidl::WireClient<Store> Synchronous client: fidl::WireSyncClient<Store> Server interface: fidl::WireServer<Store> Event handler interface: fidl::WireEventHandler<Store> | ||
| HLCPP | Client: fidl::InterfacePtr<Store> Synchronous client: fidl::SynchronousInterfacePtr<Store> Server interface: Store Event handler interface: N/A. InterfacePtr has setters that take one callback per event declaration. | ||
Here's the most common way to set up a client:
C++ (Natural)
// Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a // |zx::result| and it must be checked for errors. zx::result client_end = component::Connect<examples_canvas_baseline::Instance>(); if (!client_end.is_ok()) { FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: " << client_end.status_string(); return -1; } // Create an instance of the event handler. EventHandler event_handler(loop); // Create an asynchronous client using the newly-established connection. fidl::Client client(std::move(*client_end), dispatcher, &event_handler); FX_LOGS(INFO) << "Outgoing connection enabled";
C++ (Wire)
// Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a // |zx::result| and it must be checked for errors. zx::result client_end = component::Connect<examples_canvas_baseline::Instance>(); if (!client_end.is_ok()) { FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: " << client_end.status_string(); return -1; } // Create an instance of the event handler. EventHandler event_handler(loop); // Create an asynchronous client using the newly-established connection. fidl::WireClient client(std::move(*client_end), dispatcher, &event_handler); FX_LOGS(INFO) << "Outgoing connection enabled";
See the canvas example for the full code listing and explanation.
Here's the most common way to implement a server:
C++ (Natural)
// An implementation of the |Instance| protocol. class InstanceImpl final : public fidl::Server<examples_canvas_baseline::Instance> { void AddLine(AddLineRequest& request, AddLineCompleter::Sync& completer) override { // ... } };
C++ (Wire)
// An implementation of the |Instance| protocol. class InstanceImpl final : public fidl::WireServer<examples_canvas_baseline::Instance> { void AddLine(AddLineRequestView request, AddLineCompleter::Sync& completer) override { // ... } };
See the canvas example for the full code listing and explanation.
New C++ bindings
The new C++ bindings supports both low-level and high-level use cases, by offering two families of generated domain objects, and corresponding client and server APIs that speak those types.
Natural types
- Optimized to meet the needs of high-level service programming.
- Represent data structures using idiomatic C++ types such as std::vector,std::optional, andstd::string.
- Use smart pointers to manage heap allocated objects.
- Use zx::handleto manage handle ownership.
- Can convert data between their wire (e.g. fidl::StringView) and natural type representations (e.g.std::string).
Wire types
- Optimized to meet the needs of low-level systems programming while providing slightly more safety and features than the C bindings.
- Represent data structures whose memory layout coincides with the wire format, i.e. satisfying C++ Standard Layout. This opens the door to in-place encoding and decoding.
- Generated structures are views of an underlying buffer; they do not own memory.
- Support in-place access of FIDL messages.
- Provide fine-grained control over memory allocation.
- Use owned handle types such as zx::handle. Note that since generated structures are views of an underlying buffer, a parent structure will only own child handles if it also owns their underlying buffer. For example, a FIDL struct owns all the handles stored inline, but a FIDL vector of structs containing handles will be represented as a vector view, which will not own the out-of-line handles.
Client and server APIs
- Code generator produces more code compared to the C bindings. This includes constructors, destructors, copy/move functions, conversions between domain object families, protocol client implementations, and pure virtual server interfaces.
- Users implement a server by sub-classing a provided server interface and overriding the pure virtual methods for each operation.
- Clients supporting sync and async calls, and sync and async event handling.
- Requires C++17 or above.
Refer to the New C++ tutorial to get started.
High-level C++ bindings
- Optimized to meet the needs of high-level service programming.
- Represent data structures using idiomatic C++ types such as std::vector,std::optional, andstd::string.
- Use smart pointers to manage heap allocated objects.
- Use zx::handle(libzx) to manage handle ownership.
- Can convert data from in-place FIDL buffers to idiomatic heap allocated objects.
- Can convert data from idiomatic heap allocated objects
(e.g. std::string) to in-place buffers (e.g. as afidl::StringView).
- Code generator produces more code compared to the C bindings. This includes constructors, destructors, protocol proxies, protocol stubs, copy/move functions, and conversions to/from in-place buffers.
- Client performs protocol dispatch by sub-classing a provided stub and implementing the virtual methods for each operation.
- Both async and synchronous clients are supported. However, the async clients are not thread-safe.
- Requires C++14 or above.
Summary
| Category | New C++ with wire types | New C++ with natural types | High-level C++ | 
|---|---|---|---|
| audience | drivers and performance-critical applications | high-level services | high-level services | 
| abstraction overhead | RAII closing of handles 1 | heap allocation, construction, destruction | heap allocation, construction, destruction | 
| type safe types | enums, structs, unions, handles, protocols | enums, structs, unions, handles, protocols | enums, structs, unions, handles, protocols | 
| storage | stack, user-provided buffer, or heap | heap | heap | 
| lifecycle | manual or automatic free | automatic free (RAII) | automatic free (RAII) | 
| receive behavior | decode in-place | decode into heap | decode then move to heap | 
| send behavior | copy or vectorize | copy | copy | 
| calling protocol methods | free functions or proxy | free functions or proxy | call through proxies, register callbacks | 
| implementing protocol methods | manual dispatch or implement stub interface | implement stub interface | implement stub object, invoke callbacks | 
| async client | yes | yes | yes | 
| async server | yes (unbounded) 2 | yes (unbounded) [^2] | yes (unbounded) | 
| parallel server dispatch | yes 3 | yes [^3] | no | 
| generated code footprint | large | large | large | 
- 
Generated types own all handles stored inline. Out-of-line handles e.g. those behind a pointer indirection are not closed when the containing object of the pointer goes away. In those cases, the bindings provide a fidl::DecodedValueobject to manage all handles associated with a call. ↩
- 
The bindings library defined in lib/fidl can dispatch an unbounded number of in-flight transactions via fidl::BindServerdefined in lib/fidl/cpp/wire/channel.h. ↩
- 
The bindings library lib/fidl enables parallel dispatch using the EnableNextDispatch()API defined in lib/fidl/cpp/wire/async_transaction.h. ↩