提供可选参数的现代 C++ 方法

Rei*_*izo 33 c++ pointers optional-parameters optional semantics

让我们采用以下函数声明:

void print(SomeType const* i);
Run Code Online (Sandbox Code Playgroud)

在这里,const*参数的性质i暗示了意图,即参数是optional,因为它可能是nullptr。如果这不是故意的,那么参数将只是一个const&. 交流可选的语义当然不是设计指针的初衷,但使用它们来这样做恰好在很长一段时间内都能正常工作。

现在,由于在现代 C++ 中通常不鼓励使用原始指针(并且应该避免使用std::unique_ptrstd::shared_ptr精确指示特定的所有权 -语义),我想知道如何正确指示函数参数的可选 -语义而不传递值,即复制,作为

void print(std::optional<SomeType> i);
Run Code Online (Sandbox Code Playgroud)

会做。

考虑了一段时间后,我想出了使用的想法:

void print(std::optional<SomeType const&> i);
Run Code Online (Sandbox Code Playgroud)

这实际上是最准确的。但事实证明std::optional 不能有引用类型。¹

另外,使用

void print(std::optional<SomeType> const& i);
Run Code Online (Sandbox Code Playgroud)

决不会是最优的,从那时起,我们将要求我们SomeType在向存在std::optional主叫侧的,可能再次(或相当可能)需要复制那里

问题:那么在不复制的情况下允许可选参数的现代方法是什么?在这里使用原始指针在现代 C++ 中仍然是一种合理的方法吗?


¹:具有讽刺意味的是,所描述的为什么std::optional不能有引用类型的原因(关于重新绑定或转发赋值的争议)不适用于const引用的std::optionals的情况,因为它们不能被分配。

Joh*_*nck 24

接受一个原始指针完全没有问题,并且仍然在大量“现代”代码库中完成(我会注意到这是一个快速移动的目标)。只需对该函数发表评论,说明它允许为空,以及该函数在调用后是否持有指针的副本(即指向值的生命周期要求是什么)。

  • 事实上,在现代代码库中使用原始指针在某种意义上比以往任何时候都更清晰 - 在过去这可能意味着生命周期,但在现代 C++ 中你知道情况并非如此,因为你会使用 RAII 包装器(如“unique_ptr”) ` 转移所有权或 `shared_ptr` 在函数返回后保持生命周期)。正如您所建议的,关于生命周期的评论仍然没有什么坏处。 (8认同)
  • 我几乎总是采用 `std::span&lt;Sometype&gt;` 参数,而不是数组地址 + 长度对参数。 (2认同)

Ric*_*bob 6

函数重载在这里提供了一个干净的解决方案吗?例如,要同时声明函数的 const ref 和空参数列表版本?
这可能取决于函数体在无参数/空情况下的作用 - 以及您如何管理这两个实现以最小化代码重叠。


dar*_*une 5

原始指针通常适用于这种类型的可选参数传递,实际上是唯一一次可以整体使用原始指针的情况。这也是规范推荐的方式。

话虽如此,boost::optional确实允许您使用引用可选和常量引用可选。决定反对在std库中使用此功能(出于我在此处省略的原因)。