I need to do something a little strange with std::set_intersection and I cannot quite figure it out. I asked a similar question about a month ago, and thanks to the excellent responses to the question, I solved the issue of making the std::set_intersection work using a common link field between 2 vectors, each containing a different type of object.
The problem that I am now facing is that I am trying to get the code below to work, I basically need to write std::set_intersection's output to a new type which is effectively a union between some fields from StructA and other fields from StructB. I used a slightly modified sample written by user tclamb but it doesn't compile and I am a bit lost in the compiler errors. I am pretty sure that some of the problems I am facing are to do with the restriction that
According to the section Requirements on types in std::set_intersection InputIterator1 and InputIterator2 have the same value type. In my case this is not true, also in the case of the solution by tclamb it was also not the case, however it seemed to work.
I just edited the code below and incorporated @ivar's suggestions for some redundant code - this makes the problem easier to read - it is now compiling and running - but still producing results that are not quite what I want. The live code is also posted at coliru
#include<vector>
#include<algorithm>
#include<string>
#include <iostream>
#include <iterator>
// I wish to return a vector of these as the result
struct StructC {
std::string mCommonField;
std::string mNameFromA; // cherry picked from StructA
std::string mNameFromB; // cherry picked from StructB
float mFloatFromA; // cherry picked from StructA
int mIntFromB; // cherry picked from StructB
};
struct StructA {
// conversion operator from StructA to StructC
operator StructC() { return { mCommonField, mNameAString, "[]", mFloatValueA, 0 }; }
std::string mCommonField;
std::string mNameAString;
float mFloatValueA;
};
struct StructB {
// conversion operator from StructB to StructC
operator StructC() { return { mCommonField, "[]", mNameBString, 0.0f, mIntValueB }; }
std::string mCommonField;
std::string mNameBString;
int mIntValueB;
};
// Comparator thanks to @ivar
struct Comparator {
template<typename A, typename B>
bool operator()(const A& a, const B& b) const {
return a.mCommonField < b.mCommonField;
}
};
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, StructC const& sc) {
return os << sc.mCommonField << " - " << sc.mNameFromA << " - "
<< sc.mNameFromB << " - " << std::fixed << sc.mFloatFromA << " - " << sc.mIntFromB << std::endl;
}
int main() {
Comparator comparator;
// initially unsorted list of StructA
std::vector<StructA> aStructs = {
{"hello", "nameA1", 1.0f},
{"goodbye", "nameA2", 2.0f},
{"foo", "nameA3", 3.0f}
};
// initially unsorted list of StructB
std::vector<StructB> bStructs = {
{"hello", "nameB1", 10}, // <-- intersection as mCommonField("hello") also in aStructs
{"goodbye", "nameB2", 20}, // <-- intersection as mCommonField("goodbye") also in aStructs
{"bar", "nameB3", 30}
};
// in the above list, "hello" & "goodbye" are the common in both aStructs & bStructs
// pre-sort both sets before calling std::intersection
std::sort(aStructs.begin(), aStructs.end(), comparator);
std::sort(bStructs.begin(), bStructs.end(), comparator);
std::vector<StructC> intersection;
std::set_intersection(aStructs.begin(), aStructs.end(),
bStructs.begin(), bStructs.end(),
std::back_inserter(intersection),
comparator);
std::copy(intersection.begin(), intersection.end(),
std::ostream_iterator<StructC>(std::cout, ""));
return 0;
}