STL map compare function - can I pass a parameter?

M

Martoon

I want to instantiate an STL map with my own compare function, and I
want to pass a parameter to the compare function that will be stored
and used for all comparisons in that map instance.

As an example, let's say the map key is char* strings, and I want the
comparison based on the nth character in the string. When the map is
instantiated, I need to somehow specify n. So I might have something
like this:

class MyClass
{
public:
void MyFunction(int i);

private:
class MyCompare
{
public:
MyCompare() : m_iCharIndex(0) {}
MyCompare(int iCharIndex) : m_iCharIndex(iCharIndex) {}

bool operator()(const char* c1, const char* c2) const
{
return c1[m_iCharIndex] < c2[m_iCharIndex];
}
int m_iCharIndex;
};
};


void MyClass::MyFunction(int i)
{
// this uses default constructor for MyCompare()
std::map<const char*, float, MyCompare> myMap;

// how do I use MyCompare(i) instead?
}


I can create a map with a char* key and MyCompare as the compare
function. But what I want to do is somehow set the m_iCharIndex member
of the MyCompare class for each map that I create (so I might have one
map that keys on the 3rd character of the strings, another that keys on
the 17th character, etc.).

Is there any way that I can do something like this? I'm not actually
trying to implement an nth character compare class. That's just a
concrete example I came up with for illustration purposes. But I am
trying to find a way to pass a parameter to a compare function for each
map that I create. And that parameter will be stored and used in all
comparisons for that map instance.

Any help appreciated.
 
V

Victor Bazarov

Martoon said:
I want to instantiate an STL map with my own compare function, and I
want to pass a parameter to the compare function that will be stored
and used for all comparisons in that map instance.

As an example, let's say the map key is char* strings, and I want the
comparison based on the nth character in the string. When the map is
instantiated, I need to somehow specify n. So I might have something
like this:

class MyClass
{
public:
void MyFunction(int i);

private:
class MyCompare
{
public:
MyCompare() : m_iCharIndex(0) {}
MyCompare(int iCharIndex) : m_iCharIndex(iCharIndex) {}

You should probalby merge the two:

MyCompare(int iCharIndex = 0) : m_iCharIndex(iCharIndex) {}
bool operator()(const char* c1, const char* c2) const
{
return c1[m_iCharIndex] < c2[m_iCharIndex];
}
int m_iCharIndex;
};
};


void MyClass::MyFunction(int i)
{
// this uses default constructor for MyCompare()
std::map<const char*, float, MyCompare> myMap;

// how do I use MyCompare(i) instead?

RTFM about 'std::map's constructors.

std::map said:

V
 
M

Martoon

Thanks! That's what I was looking for. I'm reading up on the map
constructor.

There's still one point I don't quite follow, though. I can do this:

std::map<const char*, float, MyCompare> myMap(MyCompare(i));

But if I then try to use myMap, it doesn't seem to recongize it as a
map. For example,

bool b = myMap.empty();

yeilds a compiler error "left of '.empty' must have class/struct/union
type". What am I missing here?
 
V

Victor Bazarov

Martoon said:
Thanks! That's what I was looking for. I'm reading up on the map
constructor.

There's still one point I don't quite follow, though. I can do this:

std::map<const char*, float, MyCompare> myMap(MyCompare(i));

But if I then try to use myMap, it doesn't seem to recongize it as a
map. For example,

bool b = myMap.empty();

yeilds a compiler error "left of '.empty' must have class/struct/union
type". What am I missing here?

My fault! You need the second set of parentheses, otherwise it's
a function declaration:

std::map<const char*, float, MyCompare> myMap((MyCompare(i)));

V
 
K

Kai-Uwe Bux

Martoon said:
I want to instantiate an STL map with my own compare function, and I
want to pass a parameter to the compare function that will be stored
and used for all comparisons in that map instance.

As an example, let's say the map key is char* strings, and I want the
comparison based on the nth character in the string. When the map is
instantiated, I need to somehow specify n. So I might have something
like this:

class MyClass
{
public:
void MyFunction(int i);

private:
class MyCompare
{
public:
MyCompare() : m_iCharIndex(0) {}
MyCompare(int iCharIndex) : m_iCharIndex(iCharIndex) {}

bool operator()(const char* c1, const char* c2) const
{
return c1[m_iCharIndex] < c2[m_iCharIndex];
}
int m_iCharIndex;
};
};
[snip]

You have received already advice on how to get this syntactically straight.
However, the code above does no look sound: I have serious doubts that
comparing strings based on their i-th character alone yields a strict weak
ordering for the data types in your application. In other words: your
comparison predicate could cause undefined behavior in std::map.


Best

Kai-Uwe Bux
 
M

Mark P

Kai-Uwe Bux said:
Martoon said:
I want to instantiate an STL map with my own compare function, and I
want to pass a parameter to the compare function that will be stored
and used for all comparisons in that map instance.

As an example, let's say the map key is char* strings, and I want the
comparison based on the nth character in the string. When the map is
instantiated, I need to somehow specify n. So I might have something
like this:

class MyClass
{
public:
void MyFunction(int i);

private:
class MyCompare
{
public:
MyCompare() : m_iCharIndex(0) {}
MyCompare(int iCharIndex) : m_iCharIndex(iCharIndex) {}

bool operator()(const char* c1, const char* c2) const
{
return c1[m_iCharIndex] < c2[m_iCharIndex];
}
int m_iCharIndex;
};
};
[snip]

You have received already advice on how to get this syntactically straight.
However, the code above does no look sound: I have serious doubts that
comparing strings based on their i-th character alone yields a strict weak
ordering for the data types in your application.

Why do you say so? Assuming that all strings do in fact have an i-th
character, this looks like a valid strict weak ordering.

On the other hand, since a map will not allow multiple keys which
compare equal, it seems that this may not be a very useful structure,
but then only the OP knows what he wants to do with this.

Mark

In other words: your
 
K

Kai-Uwe Bux

Mark said:
Kai-Uwe Bux said:
Martoon said:
I want to instantiate an STL map with my own compare function, and I
want to pass a parameter to the compare function that will be stored
and used for all comparisons in that map instance.

As an example, let's say the map key is char* strings, and I want the
comparison based on the nth character in the string. When the map is
instantiated, I need to somehow specify n. So I might have something
like this:

class MyClass
{
public:
void MyFunction(int i);

private:
class MyCompare
{
public:
MyCompare() : m_iCharIndex(0) {}
MyCompare(int iCharIndex) : m_iCharIndex(iCharIndex) {}

bool operator()(const char* c1, const char* c2) const
{
return c1[m_iCharIndex] < c2[m_iCharIndex];
}
int m_iCharIndex;
};
};
[snip]

You have received already advice on how to get this syntactically
straight. However, the code above does no look sound: I have serious
doubts that comparing strings based on their i-th character alone yields
a strict weak ordering for the data types in your application.

Why do you say so? Assuming that all strings do in fact have an i-th
character, this looks like a valid strict weak ordering.

That is why I said "serious doubts" instead of: it will not work.

Also, from a standards point of view, the requirement is that the predicate
defines a strict weak ordering on the *type* for the keys. No restriction
is made that only the values actually used in the map have to be ordered.

On the other hand, since a map will not allow multiple keys which
compare equal, it seems that this may not be a very useful structure,
but then only the OP knows what he wants to do with this.

True, and that is why my post was carefully worded: ^^^^^

In any case, I just wanted to alert the OP of a potential pitfall in his
code. No claim on my part is made as to whether there will be trouble or
not. All I claim is that the code look somewhat dangerous.


Best

Kai-Uwe Bux
 
M

Michiel.Salters

Kai-Uwe Bux said:
I have serious doubts that comparing strings based on their i-th
character alone yields a strict weak ordering for the data types
in your application.

Any strict weak ordering of a domain Y is equivalent to a strict weak
ordering of domain X, if there is a deterministic mapping y = f(x).

In this case, the domain of strings Y is ordered by any strict weak
ordering
of optional<char> and the function optional<char> get_n(string s);

HTH,
Michiel Salters
 
K

Kai-Uwe Bux

Any strict weak ordering of a domain Y is equivalent to a strict weak
ordering of domain X, if there is a deterministic mapping y = f(x).

In this case, the domain of strings Y is ordered by any strict weak
ordering
of optional<char> and the function optional<char> get_n(string s);

Oops, my bad. I confused it for a total ordering.


Thanks

Kai-Uwe Bux
 

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
473,774
Messages
2,569,596
Members
45,135
Latest member
VeronaShap
Top