Reputation: 332
I'm trying out the C++17 optional-type, and thought a fitting place to use it would be a function that attempts to open a file and maybe returns the opened file. The function I wrote looks like this:
std::optional<std::fstream> openFile(std::string path)
{
std::fstream file;
file.open(path);
if (!file.is_open())
{
std::cerr << "couldn't open file" << path << std::endl;
return {};
}
else
{
return std::make_optional(file); // results in compilation error
}
}
But when I try to compile this with g++ with -std=c++17
as one of the arguments I get a big wall of template compilation error messages, starting with:
In file included from read_file.cpp:3:0:
/usr/include/c++/7/optional: In instantiation of ‘constexpr std::optional<typename std::decay<_Tp>::type> std::make_optional(_Tp&&) [with _Tp = std::basic_fstream<char>&; typename std::decay<_Tp>::type = std::basic_fstream<char>]’:
read_file.cpp:16:39: required from here
/usr/include/c++/7/optional:991:62: error: no matching function for call to ‘std::optional<std::basic_fstream<char> >::optional(<brace-enclosed initializer list>)’
{ return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; }
Why would it seem as if fstream
can't be used with std::optional
? Am I approaching this in the wrong way? If optional doesn't support stream-types, does that not limit where the type can be applied?
Upvotes: 4
Views: 606
Reputation: 418
Your code will try and copy the stream, when you pass it to make_optional
. Streams can't be copied, therefore, you need to move it, i.e.,
return std::make_optional(std::move(file));
or simply
return file;
(Depending on the age of the compiler, the latter might not work.)
Upvotes: 10
Reputation: 180500
std::make_optional
calls the optional constructor with the form of
template < class U = value_type >
constexpr optional( U&& value );
and that constructor behaves as doing
T optional_data = std::forward<U>(value)
which is going to make a copy since you passed an lvalue. Streams are not copyable, so you get an error. You have to move
the stream into the optional to get it to work correctly.
Upvotes: 3