Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does copy operator= exist for std::pair

Tags:

c++

I'm facing with an issue. Returning std::pair<T1, T2> from lambda function. I'm trying to generate map with opened ifstream's, but compiler complains with this output:

/usr/include/c++/9/bits/stl_algo.h:4337:12: error: use of deleted function ‘std::pair<const std::__cxx11::basic_string, std::basic_ifstream >& std::pair<const std::__cxx11::basic_string, std::basic_ifstream >::operator=(const std::pair<const std::__cxx11::basic_string, std::basic_ifstream >&)’

I went through cppref for std::pair and I didn't notice that copy operator= is not viable for this one.

I'm fairly certain that lambdas that return pair is possible, then I definitely have some misunderstanding in snippet below.

std::map<int, std::string> mFileMap;
std::map<std::string, std::ifstream> files;
std::transform(mFileMap.begin(), mFileMap.end(), files.begin(),
                [](const auto& arg) -> std::pair<std::string, std::ifstream> {
                    std::string path(arg.second);
                    std::ifstream stream(path);
                    return std::make_pair(path, stream);
                });
like image 412
nikolaus Avatar asked Dec 14 '22 07:12

nikolaus


2 Answers

std::pair is copyable only as long as whatever's in a std::pair is copyable. If you think about, for a few seconds, you will agree that this makes 100% sense.

std::pair<std::string, std::ifstream> 

std::ifstream is not copyable. You cannot copy std::ifstreams. Putting it inside a std::pair doesn't make it copyable.

But that's not the least of the problems in the shown code:

std::map<std::string, std::ifstream> files;
std::transform(mFileMap.begin(), mFileMap.end(), files.begin(),
      // ...

The files map is empty. files.begin() will return the beginning iterator to an empty map, which will be the same value as files.end(). Attempting to copy into an ending iterator (ignoring the fact that the underlying type is not copyable) will not end well.

Additionally, std::map's key is constant, in the map, so that won't work either.

This is not how stuff gets added to a map, one needs to use a std::insert_iterator.

So, to summarize, the following problems must be solved:

  1. This std::pair is not copyable.
  2. A std::insert_iterator must be used to insert new key/value pairs into a std::map.

Presuming you insist on your std::map containing these values, you'll have to do some work to populate it, using std::map::emplace, this will be the most practical way to drop new things into this map.

like image 139
Sam Varshavchik Avatar answered Feb 09 '23 21:02

Sam Varshavchik


thanks to Sam I found the way to solve this problem. So, one possible fix could be

std::map<std::string, std::ifstream> files;
std::transform(mFileMap.begin(), mFileMap.end(), std::inserter(files, files.end()),
                [](auto const& arg) -> std::pair<std::string, std::ifstream> {
                    std::string path(arg.second);
                     return std::make_pair(path, std::ifstream(path));
                  });
like image 35
nikolaus Avatar answered Feb 09 '23 21:02

nikolaus