map parameters

P

pk_pk

hi,

why is it that i am allowed to use a class or a struct for the "value"
part in a map, but not for the "key" in the pair?

i.e.

i can do this (where CMaterial is a struct) :

typedef std::map<std::string, CMaterial> MatAttr;

but i can't do:

typedef std::map<CMaterial, CMaterial> Stuff;

i realize i can do this:
typedef std::map<CMaterial*, CMaterial> Stuff;

i'm curious to know why the "key" has to be a fundamental datatype
like a pointer, float, etc.
 
M

Martin T.

pk_pk said:
hi,

why is it that i am allowed to use a class or a struct for the "value"
part in a map, but not for the "key" in the pair?

i.e.

i can do this (where CMaterial is a struct) :

typedef std::map<std::string, CMaterial> MatAttr;

but i can't do:

typedef std::map<CMaterial, CMaterial> Stuff;

i realize i can do this:
typedef std::map<CMaterial*, CMaterial> Stuff;

i'm curious to know why the "key" has to be a fundamental datatype
like a pointer, float, etc.

You *can* use it.
You just have to define the needed operations for the user defined type.
(operator<() iirc)

cheers,
Martin
 
J

Jeff Schwab

pk_pk said:
hi,

why is it that i am allowed to use a class or a struct for the "value"
part in a map, but not for the "key" in the pair?

i.e.

i can do this (where CMaterial is a struct) :

typedef std::map<std::string, CMaterial> MatAttr;

but i can't do:

typedef std::map<CMaterial, CMaterial> Stuff;

i realize i can do this:
typedef std::map<CMaterial*, CMaterial> Stuff;

i'm curious to know why the "key" has to be a fundamental datatype
like a pointer, float, etc.

Who told you that? By the way, std::string is not a fundamental
datatype, but a class type defined as part of the standard library.
 
K

Kai-Uwe Bux

pk_pk said:
hi,

why is it that i am allowed to use a class or a struct for the "value"
part in a map, but not for the "key" in the pair?

You can, but not just any class will do. There are requirements.

i can do this (where CMaterial is a struct) :

typedef std::map<std::string, CMaterial> MatAttr;

but i can't do:

typedef std::map<CMaterial, CMaterial> Stuff;

i realize i can do this:
typedef std::map<CMaterial*, CMaterial> Stuff;

i'm curious to know why the "key" has to be a fundamental datatype
like a pointer, float, etc.

It does not have to be a fundamental datatype. Note that you already used
std::string as a key.

The requirements for the type to be used as a key are (off the top of my
head):
a) KeyType has to be copy-constructible.
b) std::less<KeyType> has to be defined. The standard way of achieving that
is to have KeyType provide an operator<.

Very likely, your CMaterial does neither support operator< nor specialize
std::less.


Best

Kai-Uwe Bux
 
P

pk_pk

You can, but not just any class will do. There are requirements.







It does not have to be a fundamental datatype. Note that you already used
std::string as a key.

The requirements for the type to be used as a key are (off the top of my
head):
a) KeyType has to be copy-constructible.
b) std::less<KeyType> has to be defined. The standard way of achieving that
is to have KeyType provide an operator<.

Very likely, your CMaterial does neither support operator< nor specialize
std::less.

Best

Kai-Uwe Bux

cool, makes sense now. CMaterial doesn't support either of those. yup,
i was actually wondering why string was okay as the key.

thanks for all the replies!
kp
 
J

Juha Nieminen

Kai-Uwe Bux said:
The requirements for the type to be used as a key are (off the top of my
head):
a) KeyType has to be copy-constructible.
b) std::less<KeyType> has to be defined. The standard way of achieving that
is to have KeyType provide an operator<.

Actually std::less<KeyType> doesn't have to be defined. The
alternative is that you give the std::map instance a comparator. For
example:

struct A { int i; };

struct Comp
{
bool operator()(const A& a1, const A& a2) const
{
return a1.i < a2.i;
}
};

int main()
{
std::map<A, int, Comp> theMap((Comp()));
...
}

It's also possible to use a comparator function, although the syntax
becomes a bit more complicated (at least until the next C++ standard):

bool Comp(const A& a1, const A& a2)
{
return a1.i < a2.i;
}

int main()
{
std::map<A, int, bool(*)(const A&, const A&)> theMap(Comp);
...
}
 
J

James Kanze

You can, but not just any class will do. There are requirements.
It does not have to be a fundamental datatype. Note that you
already used std::string as a key.
The requirements for the type to be used as a key are (off the
top of my head):
a) KeyType has to be copy-constructible.

At least at present, it also has to be assignable. (I don't
think that any implementation actually requires the assignment,
except to fulfill a concept check, and I vaguely seem to
remember hearing that this requirement will be dropped in the
future.)
b) std::less<KeyType> has to be defined. The standard way of achieving that
is to have KeyType provide an operator<.

I suspect that it's more idiomatic for the user to provide a
custom comparison operator to the map. (It really depends on
the class, of course. If an operator< makes sense in general,
then you provide it. If it doesn't, however, you don't provide
one just for std::map---you define some sort of comparison type
which you specify explicitly.)
 
K

Kai-Uwe Bux

James said:
At least at present, it also has to be assignable. (I don't
think that any implementation actually requires the assignment,
except to fulfill a concept check, and I vaguely seem to
remember hearing that this requirement will be dropped in the
future.)

Since the value_type of map<S,T> is pair< const S, T >, I have to wonder
what assignability of the key-type would buy us in _any_ possible
implementation.

I suspect that it's more idiomatic for the user to provide a
custom comparison operator to the map. (It really depends on
the class, of course. If an operator< makes sense in general,
then you provide it. If it doesn't, however, you don't provide
one just for std::map---you define some sort of comparison type
which you specify explicitly.)

Well, I don't know what is more idiomatic. I routinely define operator< or
specialize std::less<> just so that my type can be used transparently in
sets and maps. In fact, I think, the compiler should just provide a default
like lexicographic ordering along members. When I start using hash maps, I
will also routinely provide a hash function. I don't think that
std::less<T> has to be natural. That it is useful is entirely sufficient
for me.


Best

Kai-Uwe Bux
 
J

James Kanze

Since the value_type of map<S,T> is pair< const S, T >, I have
to wonder what assignability of the key-type would buy us in
_any_ possible implementation.

I never said that it would buy us anything. I can't imagine a
reasonable implementation which would use it. But at least
through C++03, it's formally a requirement.

If I've understood correctly (but it's something I've not really
paid too much attention to, so I could easily be wrong here),
assignment is not necessary for any reasonable implementation of
any of the node based types (all of the associative containers,
plus std::list---and the unordered containers as well, I think),
and the requirement for it will be dropped in the next version
of the standard. (But verify with a more reliable source before
counting on it.)
Well, I don't know what is more idiomatic. I routinely define
operator< or specialize std::less<> just so that my type can
be used transparently in sets and maps. In fact, I think, the
compiler should just provide a default like lexicographic
ordering along members.

The problem with this, IMHO, is that < already has a more or
less established meaning in the minds of the reader. Long
before the STL, for example, my bit vector based set types
overloaded the relational operators for subsets: a < b meant
that a was a strict subset of b. And while I rather think that
one could qualify this as operator overloading abuse, I don't
think it's really cut and dried---my users found it natural, at
any rate. Of course, the subset relationship is *not* an
acceptable ordering for the STL. When the STL was adopted, I
provided a separate ordering relationship for it. At the other
end of the spectrum, the standard does (correctly, IMHO) not
provide relational operators for complex---I'm sure the idea of
applying < to complex numbers would shock a mathematician.

IMHO, the general rule should be that < corresponds to something
that a normal reader would call less that, and that if the type
doesn't have a natural, undisputed ordering, then < should not
be defined. And that except for strings and ordered numeric
types, the user will normally specify the ordering to be used
for std::set. I'm not opposed, however, to providing an
arbitrary ordering by means of a specialized type for this.
When I start using hash maps, I will also routinely provide a
hash function.

That's different. A hash function is, by definition, a hash
function. < is not an arbitrary strict ordering function, it
expresses a different relationship.
I don't think that std::less<T> has to be natural. That it is
useful is entirely sufficient for me.

I don't think I'd mind a specialization of std::less<T>, IF the
class doesn't define operator<. (And there's the precedence for
pointers.) Anytime the results of a < b are defined, however, I
rather think that that's what std::less should return, to avoid
confusion. Thus, it's not an option for my bitmapped sets.

More generally, what's the problem with having to specify the
ordering function? (I don't think I've ever used std::set
without specifying it. With std::map, I'd guess that 90% of the
time, the key is std::string, but if it's neither std::string or
a built-in numeric type, I tend to specify it as well.)
 
K

kratenock

hi,

why is it that i am allowed to use a class or a struct for the "value"
part in a map, but not for the "key" in the pair?

i.e.

i can do this (where CMaterial is a struct) :

typedef std::map<std::string, CMaterial> MatAttr;

but i can't do:

typedef std::map<CMaterial, CMaterial> Stuff;

i realize i can do this:
typedef std::map<CMaterial*, CMaterial> Stuff;

i'm curious to know why the "key" has to be a fundamental datatype
like a pointer, float, etc.

Hello.
A few time ago, I had a problem like that.

U should attach the header file. Your code will look like this:

#include <string>
//other includes

int main()
{
map<string, string> directory;

directory.insert(pair<string, string>("T", "555-4444"));
directory.insert(pair<string, string>("C", "555-3333"));
directory.insert(pair<string, string>("J", "555-2222"));
directory.insert(pair<string, string>("R", "555-1111"));

return (0);
}

In my way it has to work.
 
K

Kai-Uwe Bux

James said:
[snip]
Well, I don't know what is more idiomatic. I routinely define
operator< or specialize std::less<> just so that my type can
be used transparently in sets and maps. In fact, I think, the
compiler should just provide a default like lexicographic
ordering along members.

The problem with this, IMHO, is that < already has a more or
less established meaning in the minds of the reader. Long
before the STL, for example, my bit vector based set types
overloaded the relational operators for subsets: a < b meant
that a was a strict subset of b. And while I rather think that
one could qualify this as operator overloading abuse, I don't
think it's really cut and dried---my users found it natural, at
any rate. Of course, the subset relationship is *not* an
acceptable ordering for the STL. When the STL was adopted, I
provided a separate ordering relationship for it. At the other
end of the spectrum, the standard does (correctly, IMHO) not
provide relational operators for complex---I'm sure the idea of
applying < to complex numbers would shock a mathematician.

IMHO, the general rule should be that < corresponds to something
that a normal reader would call less that, and that if the type
doesn't have a natural, undisputed ordering, then < should not
be defined. And that except for strings and ordered numeric
types, the user will normally specify the ordering to be used
for std::set. I'm not opposed, however, to providing an
arbitrary ordering by means of a specialized type for this.

I agree about operator<. I did not express myself properly. When choosing
between defining operator< or specializing std::less<>, I would do the
later if there is no natural ordering.


That's different. A hash function is, by definition, a hash
function. < is not an arbitrary strict ordering function, it
expresses a different relationship.


I don't think I'd mind a specialization of std::less<T>, IF the
class doesn't define operator<. (And there's the precedence for
pointers.) Anytime the results of a < b are defined, however, I
rather think that that's what std::less should return, to avoid
confusion. Thus, it's not an option for my bitmapped sets.

Hm. You have a point here. I tend to use operator <= for partial orders like
set-inclusion (since the symmetric order is often more natural from a
mathematical point of view than the asymmetric order). Doing so, I avoid
the issue that you mentioned.

More generally, what's the problem with having to specify the
ordering function? (I don't think I've ever used std::set
without specifying it. With std::map, I'd guess that 90% of the
time, the key is std::string, but if it's neither std::string or
a built-in numeric type, I tend to specify it as well.)

To me, it's a matter of documenting intend. If I specify an ordering with
the map, I think of that as saying the order is important. If std::less<>
is implicitly used, I think of that as an implementation detail of the type
that allows it to be used as a key. I would use the first case, if the map
is used for some sorting purpose; but I would prefer the later if the
particular order in the map does not matter (other than for finding the
entry).


Best

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,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top