This is a contrived example, I know it doesn't make sense in this context. In my real case, v
contains a larger class, and I can't refactor v
due to other dependencies in the code base. Also, in the real case I'm not using std::set
but it simplifies the example. Here are two example classes A
and B
that I know don't work, and I do understand why, but hopefully will illustrate what I'm trying to do:
#include <set>
#include <vector>
using namespace std;
struct A
{
A(initializer_list<float> init) : v(init)
{
for(size_t i = 0; i < init.size(); i)
{
s.insert(i);
}
}
struct Less
{
Less(const vector<float>& v) : v(v) {};
bool operator()(size_t i, size_t j)
{
return v[i] < v[j];
}
const vector<float>& v;
};
vector<float> v;
set<size_t, Less> s;
};
struct B
{
B(initializer_list<float> init) : v(init)
{
for(size_t i = 0; i < init.size(); i)
{
s.insert(i);
}
}
template<const vector<float>& v>
struct Less
{
bool operator()(size_t i, size_t j)
{
return v[i] < v[j];
}
};
vector<float> v;
set<size_t, Less<v>> s;
};
int main()
{
A a = {1., 2., 3.};
B b = {1., 2., 3.};
}
In both cases s
contains indicies that refer to elements in v
, and Less
is trying to compare the values in v
using those indices. Is there a way to do this that I'm not seeing?
CodePudding user response:
Your A
approach is almost correct. It just needs 2 fixes:
bool operator()(size_t i, size_t j)
should beconst
.s
must have a configured functor passed to it during construction.
struct A
{
A(initializer_list<float> init) : v(init), s(v)
{
for(size_t i = 0; i < init.size(); i)
{
s.insert(i);
}
}
// These must be manually defined if you need them, the default
// ones won't be correct.
A(const A&) = delete;
A& operator=(const A&) = delete;
struct MyLess
{
MyLess(const vector<float>& v) : v(v) {};
bool operator()(size_t i, size_t j) const
{
return v[i] < v[j];
}
const vector<float>& v;
};
vector<float> v;
set<size_t, MyLess> s;
};
I'm using unordered_map so maybe your idea will still work?
Yes, the same principle applies to std::unordered_set
. You just have to pass in both hash
and key_equal
during construction. Check out the documentation to identify the correct constructor to invoke.