Reputation: 75854
All the std::make_
are made redundant by C++17 with the introduction of Class template argument deduction (except make_unique
and make_shared
).
So what is the point of std::make_optional
? As far as I can tell it does the exact same thing as the deduction guides for std::optional
.
Is there a scenario where std::make_optional
is preferred over deduction guides?
Upvotes: 35
Views: 13532
Reputation: 24788
Another example of a use for std::make_optional()
would be for constructing the object stored in a std::optional
without creating a temporary for it when its constructor takes multiple arguments.
For example, consider the following Point3D
class whose constructor has multiple arguments:
struct Point3D {
Point3D(int xx, int yy, int zz): x(xx), y(yy), z(zz) {}
int x, y, z;
};
Imagine that you want to initialize the object stored by a std::optional<Point3D>
to Point3D(1, 2, 3)
X, then you could proceed as:
std::optional oPoint = Point3D(1, 2, 3);
However, this would create a Point3D
temporary object that is then moved into the std::optional
. Instead, by using the std::make_optional()
convenience function template you can avoid the creation of that temporary:
auto oPoint = std::make_optional<Point3D>(1, 2, 3);
Since we are talking about C++17 here (i.e., std::optional
was introduced in C++17), guaranteed copy elision applies here, and therefore no Point3D
temporary object is created.
Note that you can still avoid the creation of the temporary object without using std::make_optional()
by passing std::in_place
to the constructor of the std::optional<Point3D>
object:
std::optional<Point3D> oPoint{std::in_place, 1, 2, 3};
This will construct the stored Point3D
object in place, thus avoiding the creation of a temporary. Nevertheless, you may find this more verbose than the approach with std::make_optional()
.
Xstd::optional<Point3D> oPoint(1, 2, 3);
doesn't compile.
Upvotes: 6
Reputation: 19140
One example of the difference is when you want (for whatever reason) to make an optional containing an 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>>);
}
Upvotes: 24