`std::make_optional` 有什么意义

What is the point of `std::make_optional`

C++17 通过引入 Class template argument deductionmake_uniquemake_shared 除外)使所有 std::make_ 变得多余。

那么std::make_optional? As far as I can tell it does the exact same thing as the deduction guides for std::optional有什么意义呢。

是否存在 std::make_optional 优于演绎指南的情况?

差异的一个例子是当你想要(无论出于何种原因)制作一个包含可选的可选时:

#include <optional>
#include <type_traits>

int main()
{
    auto inner=std::make_optional(325);
    auto opt2=std::make_optional(inner); // makes std::optional<std::optional<int>>
    auto opt3=std::optional(inner);      // just a copy of inner
    static_assert(std::is_same_v<decltype(opt2), std::optional<std::optional<int>>>);
    static_assert(std::is_same_v<decltype(opt3), std::optional<int>>);
}

使用 std::make_optional() 的另一个例子是构造存储在 std::optional 中的对象,当它的构造函数接受多个参数时,无需为其创建临时对象。

例如,考虑以下 Point3D class 其构造函数有多个参数:

struct Point3D {
   Point3D(int xx, int yy, int zz): x(xx), y(yy), z(zz) {}
   int x, y, z;
};

假设你想将std::optional<Point3D>存储的对象初始化为Point3D(1, 2, 3)X,那么你可以这样进行:

std::optional oPoint = Point3D(1, 2, 3);

但是,这会创建一个 Point3D 临时对象,然后将其移入 std::optional。相反,通过使用 std::make_optional() 便利函数模板,您可以避免创建该临时文件:

auto oPoint = std::make_optional<Point3D>(1, 2, 3);

由于我们在这里讨论的是 C++17(即 std::optional 是在 C++17 中引入的),保证复制省略 适用于此,因此没有 Point3D 创建临时对象。


请注意,您仍然可以通过将 std::in_place 传递给 std::optional<Point3D> 对象的构造函数来避免在不使用 std::make_optional() 的情况下创建临时对象:

std::optional<Point3D> oPoint{std::in_place, 1, 2, 3};

这将构造存储的Point3D对象就地,从而避免创建临时对象。然而,您可能会发现这比 std::make_optional().

的方法更冗长

Xstd::optional<Point3D> oPoint(1, 2, 3); 无法编译。