c++lambdaconstructoriteratorc++17

C++: Copy STL container to STL container using lambda


I could not find anything about this specific case and was wondering if it's possible at all.

I want to create a new vector of vectors out of the elements (tuples) of an unordered_set. I'm using a lambda function in the constructor for this.

struct hashFunction {
  size_t operator()(const tuple<int, int, int>& x) const {
      return get<0>(x) ^ get<1>(x) ^ get<2>(x); // Could be something else
  }
};

int main() {
    unordered_set<tuple<int, int, int>, hashFunction> mySet = {{1, 2, 3},
                                                               {4, 5, 6},
                                                               {7, 8, 9}};

    vector<vector<int>> myVector(mySet.begin(), mySet.end(), [](const tuple<int, int, int>& curTuple) {
      return vector<int>{get<0>(curTuple), get<1>(curTuple), get<2>(curTuple)};
    });

    return 0;
}

But I get:

no matching constructor for initialization of 'vector<vector<int>>'

Solution

  • No, std::vector doesn't have such a constructor. You could use std::transform to populate it after constructing it instead:

    std::vector<std::vector<int>> myVector;
    
    std::transform(mySet.begin(), mySet.end(), std::back_inserter(myVector),
                    [](const std::tuple<int, int, int>& curTuple) {
                        return std::vector<int>{std::get<0>(curTuple),
                                                std::get<1>(curTuple),
                                                std::get<2>(curTuple)};
                    });
    

    If you can use boost, there is also boost::transform_iterator that can be used in situations like this:

    #include <boost/iterator/transform_iterator.hpp>
    
    // ...
    
    auto func = [](const std::tuple<int, int, int>& curTuple) {
        return std::vector<int> {
            std::get<0>(curTuple), std::get<1>(curTuple), std::get<2>(curTuple)
        };
    };
    
    std::vector<std::vector<int>> myVector(
        boost::make_transform_iterator(mySet.begin(), func),
        boost::make_transform_iterator(mySet.end(), func));