On 02.02.2017 21:37, Joseph Hesse wrote:
> #include <set>
>
> class X
> {
> private:
> int a; // only used to make xobj's function objects
> public:
> X() : a(1) {} // WON'T WORK WITHOUT THIS
> X(int b) : a(b) {}
>
> // following makes instances of X function objects
> bool operator () (const X & x1, const X & x2) const
> { return x1.a < x2.a; }
> };
>
> int main()
> {
> std::set<X, X> s; // 2nd X because instances of X are function objects
>
> X x1(3), x2(4), x3(5);
>
> s.insert(x1);
> s.insert(x2);
> s.insert(x3);
>
> return 0;
> }
Well, the main /technical/ problem is that the std::set default
constructor, used above, in order to provide a default comparator
object, requires that the comparator type is default-constructible.
But you don't need to use an instance of your class X directly as
comparator.
You can just define an ordering of X instances by defining an
`operator<`, and then use the default comparator of `std::set`:
[code]
#include <set>
class X
{
private:
int a; // only used to make xobj's function objects
public:
//X() : a(1) {} // WORKS FINE WITHOUT THIS
X(int b) : a(b) {}
// following makes instances of X function objects
auto operator()( X const& x1, X const& x2 ) const
-> bool
{ return x1.a < x2.a; }
// This defines an ordering of X instances, that's all that
// std::set needs. The awkwardness reflects a design issue.
friend
auto operator<( X const& a, X const& b )
-> bool
{ return a.operator()( a, b ); }
};
int main()
{
X x1{ 3 };
X x2{ 4 };
X x3{ 5 };
std::set<X> s; // No 2nd X because "<" is defined for X objects.
s.insert( x1) ;
s.insert( x2 );
s.insert( x3 );
}
[/code]
• • •
A good general guideline is to separate concerns as much as practically
possible.
The X class was and is, apparently, responsible for too much, too many
concerns. I have no idea what the `a` value is all about, but a function
object class that is only about comparing instances of itself seems not
very useful, so presumably the `a` is also about something else. And the
comment on the operator definition, “makes instances”, indicates some
third purpose, that just didn't make it all the way out to the trimmed
example that you posted.
So, generally, separate concerns.
There's even a Wikipedia page about it: <url:
https://en.wikipedia.org/wiki/Separation_of_concerns>.
The `operator<` defined above is an example. It does one single job. And
it technically moves that job out of the class (except for convenience
the definition could have been placed outside the class).
Cheers & hth.,
- Alf