std::map -- Function Objects??

C

cppaddict

Hi,

I'm confused about what the comparison operator in a map template is:

In particular, I want to know why something like the following doesn't
work:

bool pointCompare(POINT p1, POINT p2) {
if (p1.y > p2.y || (p1.y == p2.y && p1.x > p2.x) )
return true;
return false;
}

int main() {
std::map<POINT,bool,pointCompare> myMap;
return 0;
}

That code won't compile, because pointCompare is not a valid
comparison operator. Below is code that does work -- it creates a
class and then defines the function operator on it. I'm unclear as to
why that method works while the one above does not.

Also, in the line:

bool operator() (const string& s1, const string& s2) const {

what is the final "const" doing there?

Thanks for any clarification,
cpp

-----WORKING CODE FOLLOWS-----

#include <iostream>
#include <iomanip>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

/* function object to compare strings
* - allows you to set the comparison criterion at runtime
* - allows you to compare case insensitive
*/
class RuntimeStringCmp {
public:
// constants for the comparison criterion
enum cmp_mode {normal, nocase};
private:
// actual comparison mode
const cmp_mode mode;

// auxiliary function to compare case insensitive
static bool nocase_compare (char c1, char c2)
{
return toupper(c1) < toupper(c2);
}

public:
// constructor: initializes the comparison criterion
RuntimeStringCmp (cmp_mode m=normal) : mode(m) {
}

// the comparison
bool operator() (const string& s1, const string& s2) const {
if (mode == normal) {
return s1<s2;
}
else {
return lexicographical_compare (s1.begin(), s1.end(),
s2.begin(), s2.end(),
nocase_compare);
}
}
};

/* container type:
* - map with
* - string keys
* - string values
* - the special comparison object type
*/
typedef map<string,string,RuntimeStringCmp> StringStringMap;
 
J

joey tribbiani

cppaddict said:
Hi,

I'm confused about what the comparison operator in a map template is:

In particular, I want to know why something like the following doesn't
work:

bool pointCompare(POINT p1, POINT p2) {
if (p1.y > p2.y || (p1.y == p2.y && p1.x > p2.x) )
return true;
return false;
}

int main() {
std::map<POINT,bool,pointCompare> myMap;
return 0;

Hi, you could just define the < for your class POINT ( you better call
it Point ) and declare the map:

std::map <Point> myMap;

class Point
{
//....
bool operator < ( Point p2 )
{
return (y > p2.y || (y == p2.y && x > p2.x);
}
}
 
R

Rolf Magnus

cppaddict said:
Hi,

I'm confused about what the comparison operator in a map template is:

In particular, I want to know why something like the following doesn't
work:

bool pointCompare(POINT p1, POINT p2) {
if (p1.y > p2.y || (p1.y == p2.y && p1.x > p2.x) )
return true;
return false;
}

int main() {
std::map<POINT,bool,pointCompare> myMap;
return 0;
}

That code won't compile, because pointCompare is not a valid
comparison operator. Below is code that does work -- it creates a
class and then defines the function operator on it. I'm unclear as to
why that method works while the one above does not.

The map expects a type as 3rd template parameter, not a pointer to
function.
Also, in the line:

bool operator() (const string& s1, const string& s2) const {

what is the final "const" doing there?

It says that the operator won't change the function object.

Btw, you mustn't change the comparison function during the life time of
a map.
 
C

cppaddict

The map expects a type as 3rd template parameter, not a pointer to
function.

So what is the minimum implementation you'd have to give the function
object? Would it be:

class RuntimeStringCmp {
// the comparison
bool operator() (const string& s1, const string& s2) const {
if (mode == normal) {
return s1<s2;
}
else {
return lexicographical_compare (s1.begin(), s1.end(),
s2.begin(), s2.end(),
nocase_compare);
}
}
};

Thanks,
cpp
 
R

Rob Williscroft

cppaddict wrote in in
comp.lang.c++:
I'm confused about what the comparison operator in a map template is:

In particular, I want to know why something like the following doesn't
work:

bool pointCompare(POINT p1, POINT p2) {
if (p1.y > p2.y || (p1.y == p2.y && p1.x > p2.x) )
return true;
return false;
}

int main() {
std::map<POINT,bool,pointCompare> myMap;
return 0;
}

That code won't compile, because pointCompare is not a valid
comparison operator.

The Compare paramiter to std::map<> is a type, this needs to be a functor
or a function-pointer type, *not* a function.

Example that works, note the typedef comp_t and the arguments passed to
map's constructor:

#include <iostream>
#include <map>

bool fless( int const &left, int const &right )
{
return left < right;
}

bool fgreater( int const &left, int const &right )
{
return right < left;
}

typedef bool (*comp_t)( int const &, int const & );

int main()
{
using namespace std;

map< int, int, comp_t > lmap( fless ), gmap( fgreater );

for ( int i = 0; i < 10; ++i )
{
lmap = gmap = i * i;
}

map< int, int, comp_t >::iterator ptr, lim;

cout << "less:\n";
for ( ptr = lmap.begin(), lim = lmap.end(); ptr != lim; ++ptr )
{
cout << ptr->first << " - " << ptr->second << "\n";
}

cout << "\ngreater:\n";
for ( ptr = gmap.begin(), lim = gmap.end(); ptr != lim; ++ptr )
{
cout << ptr->first << " - " << ptr->second << "\n";
}
}

HTH.

Rob.
 
A

Andrey Tarasevich

cppaddict said:
...
I'm confused about what the comparison operator in a map template is:

In particular, I want to know why something like the following doesn't
work:

bool pointCompare(POINT p1, POINT p2) {
if (p1.y > p2.y || (p1.y == p2.y && p1.x > p2.x) )
return true;
return false;
}

int main() {
std::map<POINT,bool,pointCompare> myMap;
return 0;
}

That code won't compile, because pointCompare is not a valid
comparison operator.

If you want to use a function pointer as a custom comparator for
'std::map', you have to declare and initialize your map as follows

std::map<POINT, bool, bool(*)(POINT, POINT)> myMap(pointCompare);

The third template parameter is the _type_ of the comparator, not the
actual instance. If you need to pass an instance of comparator to
'std::map', you have to pass it through constructor parameters.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,260
Messages
2,571,039
Members
48,768
Latest member
first4landlord

Latest Threads

Top