I am trying to use use std::set_intersection to find common elements between 2 completely different types of data structures that have a common binding \'na
Thanks to the expressiveness of C++, there are a few ways you can solve this problem. The following is by no means an exhaustive list.
If you're attached to using lambdas, define a type that can be implicitly constructed from both StructA
and StructB
and wraps the fields used for comparison. This can allow for additional logic to be performed to the fields in the constructor before comparison. For example:
struct Common {
std::string const& mCommonField;
Common(StructA const& sa) : mCommonField{sa.mCommonField} {};
Common(StructB const& sb) : mCommonField{sb.mCommonField} {};
};
Then your comparison lambda can be written
auto cmp = [](Common const& lhs, Common const& rhs) {
return lhs.mCommonField < rhs.mCommonField;
};
and used like
std::sort(aStructs.begin(), aStructs.end(), cmp);
std::sort(bStructs.begin(), bStructs.end(), cmp);
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
bStructs.begin(), bStructs.end(),
std::back_inserter(intersection),
cmp
);
Live example on Coliru Viewer.
operator()
.Instead of using a lambda, define a functor with a templated operator()
.
struct comparator
{
template
bool operator()(T const& lhs, U const& rhs) const {
return lhs.mCommonField < rhs.mCommonField;
}
};
Then, it's as easy as:
std::sort(aStructs.begin(), aStructs.end(), comparator{});
std::sort(bStructs.begin(), bStructs.end(), comparator{});
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
bStructs.begin(), bStructs.end(),
std::back_inserter(intersection),
comparator{}
);
Just note that as there is a template in the comparator, it must be declared outside of function scope. Live example on Coliru Viewer.
And with generic lambdas added to C++14, you can use the following with a conformant compiler:
auto cmp = [](auto lhs, auto rhs) { return lhs.mCommonField < rhs.mCommonField; };
// ...
std::sort(aStructs.begin(), aStructs.end(), cmp);
std::sort(bStructs.begin(), bStructs.end(), cmp);
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
bStructs.begin(), bStructs.end(),
std::back_inserter(intersection),
cmp);
Again, live example on Coliru Viewer.
Also, C-style struct typedefs are unnecessary in C++ (and arguably unclear most places in C), so anywhere you have
typedef struct Foo {
// ...
} Foo;
you can replace it with
struct Foo {
// ...
};
without any other changes required of your code.