Reputation: 11546
How can I use a comparison function object type in a method signature? Eg., this is all fine:
struct compInt {
bool operator() (const int a, const int b) { return a < b; }
};
set<int,compInt> s1;
// Actually this is no good, but removing it would obfuscate
// the accepted answer:
set<int> s2(compInt);
[The last one compiles but it's a function declaration, s2 turns out not to be a container].
But I want to do this:
void func (____ x)
{
set<int> s(x);
}
I do not want to do this:
template<typename C>
void func (C& c)
{
set<int> s(c);
}
And function<bool(const int,const int)>
does not work. I tried making compInt::operator()
virtual so I could do this:
void func (compInt& ci)
And pass in derived objects, but in fact set<int> s(ci)
then fails to compile (which I'm almost grateful for, because it is a horrid hack).
Upvotes: 1
Views: 330
Reputation: 11546
Eeroiki got me going in the right direction. What I eventually settled on was this (note the objects to be compared actually aren't ints, and a wide range of comparators could be applied to them).
using intCompFunc = std::function<bool(const int,const int)>
struct compInt {
intCompFunc comp;
bool operator() (const int a, const int b) const {
return comp(a, b);
}
void foo (intCompfunc icf)
{
compInt ci { icf };
std::set<int,compInt> s1(ci);
}
Which means the user can pass in any kind of functor, eg. a lambda:
foo([] (const int a, const int b) { return a < b; });
My confusion stems from why it isn't this way in the first place, which I think is really a historical problem (there were no C++11 functors when the STL was written). OTOH, using a base type instead of a template parameter does introduce some runtime overhead.
Upvotes: 0
Reputation: 238351
set<int> s1(compInt);
This declares a function whose return type is set<int>
.
set<int> s(x);
This declares a local variable of type set<int>
. The comparator type is not deduced from the argument, but instead the default template argument is used. As such, compInt
is not used as the comparator, so you cannot pass an instance of compInt
to the constructor.
You can use:
void func (compInt x)
{
std::set<int,compInt> s(x);
I tried making compInt::operator() virtual so I could do this:
void func (compInt& ci)
Polymorphic comparator would be quite problematic. Set stores the object by value, so passing into the function through a reference would not help. You would need to use type erasure: Define a wrapper comparator that takes a polymorphic comparator as constructor argument, stores it in dynamic storage, and delegates the call operator to the stored polymorphic comparator. Then use the wrapper type as the template argument of the set.
Upvotes: 1