Re: How do you compare char strings in an elegant way?
On Oct 7, 2:14 am, isometric_...@gmx.de wrote:
Hello,
I have this very simple task, but I cant get it to work:
there is this
std::map<const char* str, int> my_map;
and I would like to compare the requested strings using strcmp.
It works like this :
bool comp(const char* s1, const char* s2)
{
return _stricmp(s1, s2) < 0;
}
my_map(std::ptr_fun(comp));
A neat solution would be to model the function with STL functor
objects in a combination similiar to
bind2nd(less(strcmp), 0);
which is total garbage, but maybe you get the idea.
thank you
There are a number of ways. First, a few helper functions:
//this guy just prints out contents of a maps value
namespace std{
template<class K,class V>
std::ostream&operator<<(std::ostream&os,std::pair< K,V>const&p){
os<<std::setw(10)<<std::left<<p.first<<" => "<<p.second;
return os;
}
}
//some values to put into the map
char const *fruit[]={
"apple",
"Apple",
"Pear",
"orange",
"Bannana"
};
//and a conveience fucntion to load and print values into maps
template<class M>void fillandprint(M&s2i,char const*desc){
std::cout<<"\n"<<desc<<"\n";
for(int i=0;i!=sizeof(fruit)/sizeof(*fruit);++i)
s2i.insert(typename M::value_type(fruit[i],i));
std::copy(s2i.begin(),s2i.end(),
std::ostream_iterator<typename M::value_type>(std::cout,"\n"));
}
The first way, we can use a predicate functor that takes the desired
string comparator function as a template type
template<int (*Cmp)(char const*,char const*)>
struct TemplateStrCmpFun{
bool operator()(char const*l,char const*r){
return 0>Cmp(l,r);
}
};
then when we do this
std::map<char const*,int,TemplateStrCmpFun<strcmp> > mstrcmp;
fillandprint(mstrcmp,"mstrcmp");
std::map<char const*,int,TemplateStrCmpFun<_stricmp> > mstricmp;
fillandprint(mstricmp,"mstricmp");
we get this output
mstrcmp
Apple => 1
Bannana => 4
Pear => 2
apple => 0
orange => 3
mstricmp
apple => 0
Bannana => 4
orange => 3
Pear => 2
You can see that in the case insensitive version, we only have four
entries, since _stricmp("Apple","apple") is 0, and map wants unique
entries. But otherwise we get the ordering we expected.
A slightly different take on this is passing the comparator fucntion
at runtime:
struct ArgStrCmpFun{
typedef int (*CmpPtr)(char const*,char const*);
ArgStrCmpFun(CmpPtr p):Cmp(p){}
bool operator()(char const*l,char const*r){
return 0>Cmp(l,r);
}
CmpPtr Cmp;
};
and when we do this
std::map<char const*,int,ArgStrCmpFun >
mstrcmp2((ArgStrCmpFun(strcmp)));
fillandprint(mstrcmp2,"mstrcmp2");
std::map<char const*,int,ArgStrCmpFun >
mstricmp2((ArgStrCmpFun(_stricmp)));
fillandprint(mstricmp2,"mstricmp2");
we get the identical results as before. The difference here is that
now the two maps have identical types. This has a few advantages, for
example I pass these maps around via virtual functions. i.e.
struct Contrived{
virtual void foo(std::map<char const*,int,ArgStrCmpFun > const&)=0;
//type not dependent on comparator
};
but of course there is some additional overhead.
The most flexible way (in terms of sorting options) does not involve
fancy templates or such. Rather we will use the locales library:
std::map<std::string,int,std::locale >
mloc((std::locale("English_United States.1252")));
fillandprint(mloc,"mloc");
Gives us this
apple => 0
Apple => 1
Bannana => 4
orange => 3
Pear => 2
while
std::map<std::string,int,std::locale > mlocC((std::locale("C")));
fillandprint(mlocC,"mlocC");
gives us results identical to strcmp.
Hope this helps
Lance
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]