`std::make_optional` 有什么意义
What is the point of `std::make_optional`
C++17 通过引入 Class template argument deduction(make_unique
和 make_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);
无法编译。
C++17 通过引入 Class template argument deduction(make_unique
和 make_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);
无法编译。