I am iterating through a vector, and each entry in the vector has to be written to a file depending on the entry.
Let's say Vector {File A, File B, File C, File A....}
So, multiple file descriptors are open and I am storing them in a std::map
:
Key = Filename and Value = FileDescriptor. See code below.
When a Filename is not found in the map, I insert into the map a pair of data (filename, filedescriptor). The compiler is throwing an error. See error details below after the code.
std::map <std::string, std::ofstream> filemap; // maintains filename for each item in the list.
std::vector <std::string> items;
for (i=0 ; i < items.size() ; i ) {
if (keyfilemap.find(items[i]) == keyfilemap.end()) {
std::ofstream ofs (items(i), std::ofstream::out);
ofs << key.first << "-" << key.second << std::endl;
// **Compiler throws an error here.**
keyfilemap.insert(std::make_pair(filename, ofs));
}
else
keyfilemap[filename] << key.first << "-" << key.second << std::endl;
}
Compiler Error.
/usr/include/c /7/bits/stl_pair.h:529:14: error: no matching function for call to 'std::pair<std::__cxx11::basic_string<char>, std::basic_ofstream<char> >::pair(std::__cxx11::basic_string<char>&, std::basic_ofstream<char>&)'
return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y));
CodePudding user response:
C stream classes are not copyable, but you are trying to make copies when constructing your std::pair
for insert()
. That is why the code is failing to compile.
You will have to either construct the std::ofstream
objects inside the map directly, or at least transfer ownership into the map using move semantics, eg:
std::map<std::string, std::ofstream> filemap;
std::vector<std::string> items;
...
for (const auto &filename : items) {
auto iter = filemap.find(filename);
if (iter == filemap.end()) {
iter = filemap.emplace(filename, filename).first;
// or:
// iter = filemap.emplace(make_pair(filename, ofstream(filename))).first;
// or:
// std::ofstream ofs(filename);
// iter = filemap.insert(std::make_pair(filename, std::move(ofs))).first;
}
iter->second << key.first << "-" << key.second << std::endl;
}
Alternatively, just let the std::map
default-construct the std::ofstream
objects for you, and then you can open()
them when needed, eg:
std::map<std::string, std::ofstream> filemap;
std::vector<std::string> items;
...
for (const auto &filename : items) {
auto &ofs = filemap[filename];
if (!ofs.is_open()) {
ofs.open(filename);
}
ofs << key.first << "-" << key.second << std::endl;
}
CodePudding user response:
Is this perhaps what you want to achieve?:
#include <fstream>
#include <string>
#include <unordered_map>
int main()
{
std::unordered_map<std::string, std::ios_base::openmode> fname_to_fstream_pairs = {{"vacation.png", std::ofstream::out}, {"diary.txt", std::ofstream::in}};
auto const& fname_to_fstream_pair = fname_to_fstream_pairs.find("vacation.png");
if (fname_to_fstream_pair != std::end(fname_to_fstream_pairs))
{
std::ofstream ofs(fname_to_fstream_pair->first, fname_to_fstream_pair->second);
ofs << "The vacation was great!";
}
return 0;
}
std::end
denotes an element that is past the end of a container.
So, usually it == std::end(v)
is not what you want.
PS: Oh, and you shouldn't write out to a photo that way. That was just a silly example.