快速参考
下面介绍了如何识别 C++ 代码中的特定类型/函数/标识符 新 C++ 绑定或高级 C++ 绑定的一部分。
以 examples.keyvaluestore.baseline
库为例:
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;
};
下面介绍了各种 FIDL 元素在 C++ 绑定中的对应关系。注意事项 在“C++”表格中指的是新的 C++ 绑定, 自然域对象和有线域对象。“自然”是指 新的 C++ 绑定中的自然域对象。“Wire”指的是传输域 新 C++ 绑定中的对象。
FIDL 元素 | C++ 自然类型 | 评论 | |
---|---|---|---|
标题包含 | C++ | #include <fidl/examples.keyvaluestore.baseline/cpp/fidl.h> | 格式为 `fidl/library name/cpp/fidl.h` |
HLCPP | #include <examples/keyvaluestore/baseline/cpp/fidl.h> | 格式为 `正斜线分隔的库名称/cpp/fidl.h` | |
图书馆 | C++ | ::examples_keyvaluestore_baseline | 新的 C++ 使用单级命名空间。 HLCPP 使用嵌套命名空间。 |
HLCPP | ::examples::keyvaluestore::baseline | ||
商品结构 | 自然 | ::examples_keyvaluestore_baseline::Item | 除了命名空间差异之外,电线类型嵌套在“::wire”下。 |
金属丝 | ::examples_keyvaluestore_baseline::wire::Item | ||
HLCPP | ::examples::keyvaluestore::baseline::Item | ||
WriteError 枚举 | 自然 | ::examples_keyvaluestore_baseline::WriteError | 除了命名空间差异之外,导线类型嵌套在“::wire”下。 对于枚举和位,导线类型和自然类型是等效的。只有一个额外的类型别名。 |
金属丝 | ::examples_keyvaluestore_baseline::wire::WriteError | ||
HLCPP | ::examples::keyvaluestore::baseline::WriteError | ||
string:128 | 自然 | std::string | |
金属丝 | fidl::StringView | ||
HLCPP | std::string | ||
vector<byte>:64000 | 自然 | std::vector<uint8_t> | |
金属丝 | fidl::VectorView<uint8_t> | ||
HLCPP | std::vector<uint8_t> | ||
协议存储区 | C++ | ::examples_keyvaluestore_baseline::Store | 一种标记类型,包含协议的一些相关信息 |
HLCPP | ::examples::keyvaluestore::baseline::Store | 包含协议中方法的抽象基类 | |
client_end:Store | C++ | fidl::ClientEnd<Store> | |
HLCPP | fidl::InterfaceHandle<Store> | ||
server_end:Store | C++ | fidl::ServerEnd<Store> | |
HLCPP | fidl::InterfaceRequest<Store> | ||
商店协议对应的 客户端和服务器类型 |
自然 | 客户端:fidl::Client<Store> 同步客户端:fidl::SyncClient<Store> 服务器接口:fidl::Server<Store> 事件处理脚本接口:fidl::EventHandler<Store> |
|
金属丝 | 客户端:fidl::WireClient<Store> 同步客户端:fidl::WireSyncClient<Store> 服务器接口:fidl::WireServer<Store> 事件处理脚本接口:fidl::WireEventHandler<Store> |
||
HLCPP | 客户端:fidl::InterfacePtr<Store> 同步客户端:fidl::SynchronousInterfacePtr<Store> 服务器接口:Store 事件处理脚本接口:不适用。InterfacePtr 的 setter 会针对每个事件声明接受一个回调。 |
以下是设置客户端的最常用方法:
C++(自然)
// 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++(有线)
// 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";
HLCPP
// Connect to the protocol inside the component's namespace, then create an asynchronous client // using the newly-established connection. examples::canvas::baseline::InstancePtr instance_proxy; auto context = sys::ComponentContext::Create(); context->svc()->Connect(instance_proxy.NewRequest(dispatcher)); FX_LOGS(INFO) << "Outgoing connection enabled"; instance_proxy.set_error_handler([&loop](zx_status_t status) { FX_LOGS(ERROR) << "Shutdown unexpectedly"; loop.Quit(); });
如需查看完整的代码列表和说明,请参阅 canvas 示例。
以下是实现服务器的最常用方法:
C++(自然)
// 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++(有线)
// An implementation of the |Instance| protocol. class InstanceImpl final : public fidl::WireServer<examples_canvas_baseline::Instance> { void AddLine(AddLineRequestView request, AddLineCompleter::Sync& completer) override { // ... } };
HLCPP
// An implementation of the |Instance| protocol. class InstanceImpl final : public examples::canvas::baseline::Instance { void AddLine(Line line) override { // ... } };
如需查看完整的代码列表和说明,请参阅 canvas 示例。
新的 C++ 绑定
新的 C++ 绑定同时支持低层级和高层级用例,具体方法是 提供了两个生成的域对象系列,以及相应的客户端和 支持这些类型的服务器 API。
自然类型
- 经过优化,可满足高级服务编排的需求。
- 使用惯用的 C++ 类型(例如
std::vector
)表示数据结构,std::optional
和std::string
。 - 使用智能指针管理堆分配的对象。
- 使用
zx::handle
管理所有权。 - 可以在线缆(例如
fidl::StringView
)和自然线之间转换数据 类型表示法(例如std::string
)。
电汇类型
- 经过优化,可满足低级别系统编程的需求,同时提供 安全性和功能略高于 C 绑定。
- 表示内存布局与电线重合的数据结构 格式,即满足 C++ 标准布局的要求。这将打开 就地编码和解码。
- 生成的结构是底层缓冲区的视图;不归自己所有 内存。
- 支持就地访问 FIDL 消息。
- 提供对内存分配的精细控制。
- 使用自有标识名类型,例如
zx::handle
。请注意,由于生成了 结构是底层缓冲区的视图,因此父结构只会 自身的子级句柄,前提是它也拥有其底层缓冲区。例如, FIDL 结构体拥有内嵌存储的所有句柄,但 FIDL 结构体拥有结构体向量 包含的手柄将表示为矢量视图,该视图不会拥有 执行脱线句柄
客户端和服务器 API
- 与 C 绑定相比,代码生成器生成的代码更多。这包括 构造函数、析构函数、复制/移动函数、域之间的转换 对象系列、协议客户端实现和纯虚拟服务器 界面。
- 用户通过为提供的服务器接口创建子类来实现服务器,以及 为每项操作替换纯虚方法。
- 支持同步和异步调用以及支持同步和异步事件处理的客户端。
- 需要 C++17 或更高版本。
如需开始使用,请参阅新建 C++ 教程。
高级 C++ 绑定
- 经过优化,可满足高级服务编排的需求。
- 使用惯用的 C++ 类型(例如
std::vector
)表示数据结构,std::optional
和std::string
。 - 使用智能指针管理堆分配的对象。
- 使用
zx::handle
(libzx) 管理处理所有权。 - 可以将数据从就地 FIDL 缓冲区转换为惯用的分配堆 对象的操作。
- 可以从惯用的堆分配对象转换数据
(例如
std::string
)添加到就地缓冲区(例如,作为fidl::StringView
)。 - 与 C 绑定相比,代码生成器生成的代码更多。这包括 构造函数、析构函数、协议代理、协议存根、复制/移动 函数,以及与就地缓冲区之间的转换。
- 客户端通过对提供的存根进行子类化来执行协议调度,并 为每项操作实现虚拟方法。
- 异步和同步客户端均受支持。不过,异步客户端 不是线程安全的。
- 需要 C++14 或更高版本。
如需开始使用,请参阅 HLCPP 教程。
摘要
类别 | 包含线型的新 C++ | 使用自然类型的新 C++ | 高阶 C++ |
---|---|---|---|
受众群体 | 驱动程序和性能关键型应用 | 高级服务 | 高级服务 |
抽象开销 | 手柄的 RAII 关闭 1 | 堆分配、构建、销毁 | 堆分配、构建、销毁 |
类型安全类型 | 枚举、结构体、联合、句柄、协议 | 枚举、结构体、联合、句柄、协议 | 枚举、结构体、联合、句柄、协议 |
存储空间 | 堆栈、用户提供的缓冲区或堆 | 堆 | 堆 |
lifecycle | 手动或自动释放 | 自动释放 (RAII) | 自动释放 (RAII) |
接收行为 | 就地解码 | 解码为堆 | 解码然后移至堆 |
发送行为 | 复制或矢量化 | 复制 | 复制 |
调用协议方法 | 免费函数或代理 | 免费函数或代理 | 通过代理调用、注册回调 |
实现协议方法 | 手动调度或实现桩接口 | 实现桩接口 | 实现桩对象、调用回调 |
异步客户端 | 是 | 是 | 是 |
异步服务器 | yes(无界限)2 | 是(无限制)[^2] | yes(无界限) |
并行服务器调度 | 是3 | 是 [^3] | 否 |
生成的代码占用空间 | 大 | 大 | 大 |
-
生成的类型拥有所有内嵌存储的标识名。非在线标识名 例如包含 对象会消失。在这些情况下,这些绑定提供了一个
fidl::DecodedValue
对象来管理与通话相关联的所有句柄。↩ -
在 lib/fidl 中定义的绑定库可以 通过
fidl::BindServer
分派无限数量的进行中事务 定义于 lib/fidl/cpp/wire/channel.h.↩ -
绑定库 lib/fidl 支持并行
EnableNextDispatch()
API 进行调度, lib/fidl/cpp/wire/async_transaction.h.↩